commit 7172076650b639a471c97632f83c3e6431c3b2bd Author: Indy970 Date: Sun Feb 10 15:32:15 2019 +0200 First Commit diff --git a/QtHPConnect.pro b/QtHPConnect.pro new file mode 100644 index 0000000..a98fcd0 --- /dev/null +++ b/QtHPConnect.pro @@ -0,0 +1,34 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-01-21T20:42:03 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = QtHPConnect +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui diff --git a/data.cpp b/data.cpp new file mode 100644 index 0000000..02f9465 --- /dev/null +++ b/data.cpp @@ -0,0 +1,6 @@ +#include "data.h" + +data::data() +{ + +} diff --git a/data.h b/data.h new file mode 100644 index 0000000..63f2ed6 --- /dev/null +++ b/data.h @@ -0,0 +1,11 @@ +#ifndef DATA_H +#define DATA_H + + +class data +{ +public: + data(); +}; + +#endif // DATA_H \ No newline at end of file diff --git a/datamodel.cpp b/datamodel.cpp new file mode 100644 index 0000000..1a9dd2c --- /dev/null +++ b/datamodel.cpp @@ -0,0 +1,6 @@ +#include "datamodel.h" + +dataModel::dataModel() +{ + +} diff --git a/datamodel.h b/datamodel.h new file mode 100644 index 0000000..c783851 --- /dev/null +++ b/datamodel.h @@ -0,0 +1,11 @@ +#ifndef DATAMODEL_H +#define DATAMODEL_H + + +class dataModel +{ +public: + dataModel(); +}; + +#endif // DATAMODEL_H \ No newline at end of file diff --git a/errorhandler.cpp b/errorhandler.cpp new file mode 100644 index 0000000..88f5800 --- /dev/null +++ b/errorhandler.cpp @@ -0,0 +1,6 @@ +#include "errorhandler.h" + +errorHandler::errorHandler() +{ + +} diff --git a/errorhandler.h b/errorhandler.h new file mode 100644 index 0000000..33d3edd --- /dev/null +++ b/errorhandler.h @@ -0,0 +1,12 @@ +#ifndef ERRORHANDLER_H +#define ERRORHANDLER_H + +#include + +class errorHandler +{ +public: + errorHandler(); +}; + +#endif // ERRORHANDLER_H \ No newline at end of file diff --git a/getnumber.cpp b/getnumber.cpp new file mode 100644 index 0000000..041c613 --- /dev/null +++ b/getnumber.cpp @@ -0,0 +1,14 @@ +#include "getnumber.h" +#include "ui_getnumber.h" + +getNumber::getNumber(QWidget *parent) : + QDialog(parent), + ui(new Ui::getNumber) +{ + ui->setupUi(this); +} + +getNumber::~getNumber() +{ + delete ui; +} diff --git a/getnumber.h b/getnumber.h new file mode 100644 index 0000000..2b45769 --- /dev/null +++ b/getnumber.h @@ -0,0 +1,22 @@ +#ifndef GETNUMBER_H +#define GETNUMBER_H + +#include + +namespace Ui { +class getNumber; +} + +class getNumber : public QDialog +{ + Q_OBJECT + +public: + explicit getNumber(QWidget *parent = 0); + ~getNumber(); + +private: + Ui::getNumber *ui; +}; + +#endif // GETNUMBER_H diff --git a/getnumber.ui b/getnumber.ui new file mode 100644 index 0000000..18aa312 --- /dev/null +++ b/getnumber.ui @@ -0,0 +1,67 @@ + + getNumber + + + + 0 + 0 + 640 + 480 + + + + Dialog + + + + + 10 + 440 + 621 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + buttonBox + accepted() + getNumber + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + getNumber + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/global.h b/global.h new file mode 100644 index 0000000..e84f8a8 --- /dev/null +++ b/global.h @@ -0,0 +1,4 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#endif // GLOBAL_H diff --git a/hidapi.h/hidapi.h b/hidapi.h/hidapi.h new file mode 100644 index 0000000..e5bc2dc --- /dev/null +++ b/hidapi.h/hidapi.h @@ -0,0 +1,391 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 8/22/2009 + + Copyright 2009, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU General Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +/** @file + * @defgroup API hidapi API + */ + +#ifndef HIDAPI_H__ +#define HIDAPI_H__ + +#include + +#ifdef _WIN32 + #define HID_API_EXPORT __declspec(dllexport) + #define HID_API_CALL +#else + #define HID_API_EXPORT /**< API export macro */ + #define HID_API_CALL /**< API call macro */ +#endif + +#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ + +#ifdef __cplusplus +extern "C" { +#endif + struct hid_device_; + typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ + + /** hidapi info structure */ + struct hid_device_info { + /** Platform-specific device path */ + char *path; + /** Device Vendor ID */ + unsigned short vendor_id; + /** Device Product ID */ + unsigned short product_id; + /** Serial Number */ + wchar_t *serial_number; + /** Device Release Number in binary-coded decimal, + also known as Device Version Number */ + unsigned short release_number; + /** Manufacturer String */ + wchar_t *manufacturer_string; + /** Product string */ + wchar_t *product_string; + /** Usage Page for this Device/Interface + (Windows/Mac only). */ + unsigned short usage_page; + /** Usage for this Device/Interface + (Windows/Mac only).*/ + unsigned short usage; + /** The USB interface which this logical device + represents. Valid on both Linux implementations + in all cases, and valid on the Windows implementation + only if the device contains more than one interface. */ + int interface_number; + + /** Pointer to the next device */ + struct hid_device_info *next; + }; + + + /** @brief Initialize the HIDAPI library. + + This function initializes the HIDAPI library. Calling it is not + strictly necessary, as it will be called automatically by + hid_enumerate() and any of the hid_open_*() functions if it is + needed. This function should be called at the beginning of + execution however, if there is a chance of HIDAPI handles + being opened by different threads simultaneously. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_init(void); + + /** @brief Finalize the HIDAPI library. + + This function frees all of the static data associated with + HIDAPI. It should be called at the end of execution to avoid + memory leaks. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_exit(void); + + /** @brief Enumerate the HID Devices. + + This function returns a linked list of all the HID devices + attached to the system which match vendor_id and product_id. + If @p vendor_id is set to 0 then any vendor matches. + If @p product_id is set to 0 then any product matches. + If @p vendor_id and @p product_id are both set to 0, then + all HID devices will be returned. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the types of device + to open. + @param product_id The Product ID (PID) of the types of + device to open. + + @returns + This function returns a pointer to a linked list of type + struct #hid_device, containing information about the HID devices + attached to the system, or NULL in the case of failure. Free + this linked list by calling hid_free_enumeration(). + */ + struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); + + /** @brief Free an enumeration Linked List + + This function frees a linked list created by hid_enumerate(). + + @ingroup API + @param devs Pointer to a list of struct_device returned from + hid_enumerate(). + */ + void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); + + /** @brief Open a HID device using a Vendor ID (VID), Product ID + (PID) and optionally a serial number. + + If @p serial_number is NULL, the first device with the + specified VID and PID is opened. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the device to open. + @param product_id The Product ID (PID) of the device to open. + @param serial_number The Serial Number of the device to open + (Optionally NULL). + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); + + /** @brief Open a HID device by its path name. + + The path name be determined by calling hid_enumerate(), or a + platform-specific path name can be used (eg: /dev/hidraw0 on + Linux). + + @ingroup API + @param path The path name of the device to open + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); + + /** @brief Write an Output report to a HID device. + + The first byte of @p data[] must contain the Report ID. For + devices which only support a single report, this must be set + to 0x0. The remaining bytes contain the report data. Since + the Report ID is mandatory, calls to hid_write() will always + contain one more byte than the report contains. For example, + if a hid report is 16 bytes long, 17 bytes must be passed to + hid_write(), the Report ID (or 0x0, for devices with a + single report), followed by the report data (16 bytes). In + this example, the length passed in would be 17. + + hid_write() will send the data on the first OUT endpoint, if + one exists. If it does not, it will send the data through + the Control Endpoint (Endpoint 0). + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Read an Input report from a HID device with timeout. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + @param milliseconds timeout in milliseconds or -1 for blocking wait. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read within + the timeout period, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); + + /** @brief Read an Input report from a HID device. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read and + the handle is in non-blocking mode, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); + + /** @brief Set the device handle to be non-blocking. + + In non-blocking mode calls to hid_read() will return + immediately with a value of 0 if there is no data to be + read. In blocking mode, hid_read() will wait (block) until + there is data to read before returning. + + Nonblocking can be turned on and off at any time. + + @ingroup API + @param device A device handle returned from hid_open(). + @param nonblock enable or not the nonblocking reads + - 1 to enable nonblocking + - 0 to disable nonblocking. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); + + /** @brief Send a Feature report to the device. + + Feature reports are sent over the Control endpoint as a + Set_Report transfer. The first byte of @p data[] must + contain the Report ID. For devices which only support a + single report, this must be set to 0x0. The remaining bytes + contain the report data. Since the Report ID is mandatory, + calls to hid_send_feature_report() will always contain one + more byte than the report contains. For example, if a hid + report is 16 bytes long, 17 bytes must be passed to + hid_send_feature_report(): the Report ID (or 0x0, for + devices which do not use numbered reports), followed by the + report data (16 bytes). In this example, the length passed + in would be 17. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send, including + the report number. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Get a feature report from a HID device. + + Set the first byte of @p data[] to the Report ID of the + report to be read. Make sure to allow space for this + extra byte in @p data[]. Upon return, the first byte will + still contain the Report ID, and the report data will + start in data[1]. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into, including + the Report ID. Set the first byte of @p data[] to the + Report ID of the report to be read, or set it to zero + if your device does not use numbered reports. + @param length The number of bytes to read, including an + extra byte for the report ID. The buffer can be longer + than the actual report. + + @returns + This function returns the number of bytes read plus + one for the report ID (which is still in the first + byte), or -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); + + /** @brief Close a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + */ + void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); + + /** @brief Get The Manufacturer String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Product String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Serial Number String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get a string from a HID device, based on its string index. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string_index The index of the string to get. + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); + + /** @brief Get a string describing the last error which occurred. + + @ingroup API + @param device A device handle returned from hid_open(). + + @returns + This function returns a string containing the last error + which occurred or NULL if none has occurred. + */ + HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/hidapi/hidapi.h b/hidapi/hidapi.h new file mode 100644 index 0000000..e5bc2dc --- /dev/null +++ b/hidapi/hidapi.h @@ -0,0 +1,391 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 8/22/2009 + + Copyright 2009, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU General Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +/** @file + * @defgroup API hidapi API + */ + +#ifndef HIDAPI_H__ +#define HIDAPI_H__ + +#include + +#ifdef _WIN32 + #define HID_API_EXPORT __declspec(dllexport) + #define HID_API_CALL +#else + #define HID_API_EXPORT /**< API export macro */ + #define HID_API_CALL /**< API call macro */ +#endif + +#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ + +#ifdef __cplusplus +extern "C" { +#endif + struct hid_device_; + typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ + + /** hidapi info structure */ + struct hid_device_info { + /** Platform-specific device path */ + char *path; + /** Device Vendor ID */ + unsigned short vendor_id; + /** Device Product ID */ + unsigned short product_id; + /** Serial Number */ + wchar_t *serial_number; + /** Device Release Number in binary-coded decimal, + also known as Device Version Number */ + unsigned short release_number; + /** Manufacturer String */ + wchar_t *manufacturer_string; + /** Product string */ + wchar_t *product_string; + /** Usage Page for this Device/Interface + (Windows/Mac only). */ + unsigned short usage_page; + /** Usage for this Device/Interface + (Windows/Mac only).*/ + unsigned short usage; + /** The USB interface which this logical device + represents. Valid on both Linux implementations + in all cases, and valid on the Windows implementation + only if the device contains more than one interface. */ + int interface_number; + + /** Pointer to the next device */ + struct hid_device_info *next; + }; + + + /** @brief Initialize the HIDAPI library. + + This function initializes the HIDAPI library. Calling it is not + strictly necessary, as it will be called automatically by + hid_enumerate() and any of the hid_open_*() functions if it is + needed. This function should be called at the beginning of + execution however, if there is a chance of HIDAPI handles + being opened by different threads simultaneously. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_init(void); + + /** @brief Finalize the HIDAPI library. + + This function frees all of the static data associated with + HIDAPI. It should be called at the end of execution to avoid + memory leaks. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_exit(void); + + /** @brief Enumerate the HID Devices. + + This function returns a linked list of all the HID devices + attached to the system which match vendor_id and product_id. + If @p vendor_id is set to 0 then any vendor matches. + If @p product_id is set to 0 then any product matches. + If @p vendor_id and @p product_id are both set to 0, then + all HID devices will be returned. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the types of device + to open. + @param product_id The Product ID (PID) of the types of + device to open. + + @returns + This function returns a pointer to a linked list of type + struct #hid_device, containing information about the HID devices + attached to the system, or NULL in the case of failure. Free + this linked list by calling hid_free_enumeration(). + */ + struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); + + /** @brief Free an enumeration Linked List + + This function frees a linked list created by hid_enumerate(). + + @ingroup API + @param devs Pointer to a list of struct_device returned from + hid_enumerate(). + */ + void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); + + /** @brief Open a HID device using a Vendor ID (VID), Product ID + (PID) and optionally a serial number. + + If @p serial_number is NULL, the first device with the + specified VID and PID is opened. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the device to open. + @param product_id The Product ID (PID) of the device to open. + @param serial_number The Serial Number of the device to open + (Optionally NULL). + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); + + /** @brief Open a HID device by its path name. + + The path name be determined by calling hid_enumerate(), or a + platform-specific path name can be used (eg: /dev/hidraw0 on + Linux). + + @ingroup API + @param path The path name of the device to open + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); + + /** @brief Write an Output report to a HID device. + + The first byte of @p data[] must contain the Report ID. For + devices which only support a single report, this must be set + to 0x0. The remaining bytes contain the report data. Since + the Report ID is mandatory, calls to hid_write() will always + contain one more byte than the report contains. For example, + if a hid report is 16 bytes long, 17 bytes must be passed to + hid_write(), the Report ID (or 0x0, for devices with a + single report), followed by the report data (16 bytes). In + this example, the length passed in would be 17. + + hid_write() will send the data on the first OUT endpoint, if + one exists. If it does not, it will send the data through + the Control Endpoint (Endpoint 0). + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Read an Input report from a HID device with timeout. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + @param milliseconds timeout in milliseconds or -1 for blocking wait. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read within + the timeout period, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); + + /** @brief Read an Input report from a HID device. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read and + the handle is in non-blocking mode, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); + + /** @brief Set the device handle to be non-blocking. + + In non-blocking mode calls to hid_read() will return + immediately with a value of 0 if there is no data to be + read. In blocking mode, hid_read() will wait (block) until + there is data to read before returning. + + Nonblocking can be turned on and off at any time. + + @ingroup API + @param device A device handle returned from hid_open(). + @param nonblock enable or not the nonblocking reads + - 1 to enable nonblocking + - 0 to disable nonblocking. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); + + /** @brief Send a Feature report to the device. + + Feature reports are sent over the Control endpoint as a + Set_Report transfer. The first byte of @p data[] must + contain the Report ID. For devices which only support a + single report, this must be set to 0x0. The remaining bytes + contain the report data. Since the Report ID is mandatory, + calls to hid_send_feature_report() will always contain one + more byte than the report contains. For example, if a hid + report is 16 bytes long, 17 bytes must be passed to + hid_send_feature_report(): the Report ID (or 0x0, for + devices which do not use numbered reports), followed by the + report data (16 bytes). In this example, the length passed + in would be 17. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send, including + the report number. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Get a feature report from a HID device. + + Set the first byte of @p data[] to the Report ID of the + report to be read. Make sure to allow space for this + extra byte in @p data[]. Upon return, the first byte will + still contain the Report ID, and the report data will + start in data[1]. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into, including + the Report ID. Set the first byte of @p data[] to the + Report ID of the report to be read, or set it to zero + if your device does not use numbered reports. + @param length The number of bytes to read, including an + extra byte for the report ID. The buffer can be longer + than the actual report. + + @returns + This function returns the number of bytes read plus + one for the report ID (which is still in the first + byte), or -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); + + /** @brief Close a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + */ + void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); + + /** @brief Get The Manufacturer String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Product String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Serial Number String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get a string from a HID device, based on its string index. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string_index The index of the string to get. + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); + + /** @brief Get a string describing the last error which occurred. + + @ingroup API + @param device A device handle returned from hid_open(). + + @returns + This function returns a string containing the last error + which occurred or NULL if none has occurred. + */ + HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/hp_infodialog.cpp b/hp_infodialog.cpp new file mode 100644 index 0000000..a8ab594 --- /dev/null +++ b/hp_infodialog.cpp @@ -0,0 +1,14 @@ +#include "hp_infodialog.h" +#include "ui_hp_infodialog.h" + +hp_infoDialog::hp_infoDialog(QWidget *parent) : + QFrame(parent), + ui(new Ui::hp_infoDialog) +{ + ui->setupUi(this); +} + +hp_infoDialog::~hp_infoDialog() +{ + delete ui; +} diff --git a/hp_infodialog.h b/hp_infodialog.h new file mode 100644 index 0000000..8f323e3 --- /dev/null +++ b/hp_infodialog.h @@ -0,0 +1,22 @@ +#ifndef HP_INFODIALOG_H +#define HP_INFODIALOG_H + +#include + +namespace Ui { +class hp_infoDialog; +} + +class hp_infoDialog : public QFrame +{ + Q_OBJECT + +public: + explicit hp_infoDialog(QWidget *parent = 0); + ~hp_infoDialog(); + +private: + Ui::hp_infoDialog *ui; +}; + +#endif // HP_INFODIALOG_H diff --git a/hp_infodialog.ui b/hp_infodialog.ui new file mode 100644 index 0000000..dbe10ff --- /dev/null +++ b/hp_infodialog.ui @@ -0,0 +1,17 @@ + + + hp_infoDialog + + + + 0 + 0 + 640 + 480 + + + + Frame + + + diff --git a/hp_mditexteditor.cpp b/hp_mditexteditor.cpp new file mode 100644 index 0000000..6549179 --- /dev/null +++ b/hp_mditexteditor.cpp @@ -0,0 +1,6 @@ +#include "hp_mditexteditor.h" + +hp_mdiTextEditor::hp_mdiTextEditor() +{ + +} diff --git a/hp_mditexteditor.h b/hp_mditexteditor.h new file mode 100644 index 0000000..ab64948 --- /dev/null +++ b/hp_mditexteditor.h @@ -0,0 +1,13 @@ +#ifndef HP_MDITEXTEDITOR_H +#define HP_MDITEXTEDITOR_H + +#include +#include + +class hp_mdiTextEditor +{ +public: + hp_mdiTextEditor(); +}; + +#endif // HP_MDITEXTEDITOR_H \ No newline at end of file diff --git a/hp_mdivariableedit.cpp b/hp_mdivariableedit.cpp new file mode 100644 index 0000000..8da3d64 --- /dev/null +++ b/hp_mdivariableedit.cpp @@ -0,0 +1,6 @@ +#include "hp_mdivariableedit.h" + +hp_mdiVariableEdit::hp_mdiVariableEdit(QWidget *parent) : QWidget(parent) +{ + +} diff --git a/hp_mdivariableedit.h b/hp_mdivariableedit.h new file mode 100644 index 0000000..a6e8b4b --- /dev/null +++ b/hp_mdivariableedit.h @@ -0,0 +1,18 @@ +#ifndef HP_MDIVARIABLEEDIT_H +#define HP_MDIVARIABLEEDIT_H + +#include +#include + +class hp_mdiVariableEdit : public QWidget +{ + Q_OBJECT +public: + explicit hp_mdiVariableEdit(QWidget *parent = nullptr); + +signals: + +public slots: +}; + +#endif // HP_MDIVARIABLEEDIT_H \ No newline at end of file diff --git a/hp_mdiwindow.cpp b/hp_mdiwindow.cpp new file mode 100644 index 0000000..ff37632 --- /dev/null +++ b/hp_mdiwindow.cpp @@ -0,0 +1,6 @@ +#include "hp_mdiwindow.h" + +hp_MDIWindow::hp_MDIWindow() +{ + +} diff --git a/hp_mdiwindow.h b/hp_mdiwindow.h new file mode 100644 index 0000000..c6d226a --- /dev/null +++ b/hp_mdiwindow.h @@ -0,0 +1,13 @@ +#ifndef HP_MDIWINDOW_H +#define HP_MDIWINDOW_H + +#include +#include + +class hp_MDIWindow +{ +public: + hp_MDIWindow(); +}; + +#endif // HP_MDIWINDOW_H \ No newline at end of file diff --git a/hp_mdiwindow.ui b/hp_mdiwindow.ui new file mode 100644 index 0000000..0439df4 --- /dev/null +++ b/hp_mdiwindow.ui @@ -0,0 +1,25 @@ + + + + + + MainWindow + + + + 0 + 0 + 640 + 480 + + + + MainWindow + + + + + + + + diff --git a/hpdata.cpp b/hpdata.cpp new file mode 100644 index 0000000..ce1a962 --- /dev/null +++ b/hpdata.cpp @@ -0,0 +1,6 @@ +#include "hpdata.h" + +hpData::hpData() +{ + +} diff --git a/hpdata.h b/hpdata.h new file mode 100644 index 0000000..d9da67f --- /dev/null +++ b/hpdata.h @@ -0,0 +1,12 @@ +#ifndef HPDATA_H +#define HPDATA_H + +#include + +class hpData +{ +public: + hpData(); +}; + +#endif // HPDATA_H \ No newline at end of file diff --git a/hpinterface.h b/hpinterface.h new file mode 100644 index 0000000..52f030a --- /dev/null +++ b/hpinterface.h @@ -0,0 +1,4 @@ +#ifndef HPINTERFACE_H +#define HPINTERFACE_H + +#endif // HPINTERFACE_H diff --git a/hptoolbox.cpp b/hptoolbox.cpp new file mode 100644 index 0000000..e9645a5 --- /dev/null +++ b/hptoolbox.cpp @@ -0,0 +1,14 @@ +#include "hptoolbox.h" +#include "ui_hptoolbox.h" + +hpToolBox::hpToolBox(QWidget *parent) : + QToolBox(parent), + ui(new Ui::hpToolBox) +{ + ui->setupUi(this); +} + +hpToolBox::~hpToolBox() +{ + delete ui; +} diff --git a/hptoolbox.h b/hptoolbox.h new file mode 100644 index 0000000..b8c1ec0 --- /dev/null +++ b/hptoolbox.h @@ -0,0 +1,22 @@ +#ifndef HPTOOLBOX_H +#define HPTOOLBOX_H + +#include + +namespace Ui { +class hpToolBox; +} + +class hpToolBox : public QToolBox +{ + Q_OBJECT + +public: + explicit hpToolBox(QWidget *parent = 0); + ~hpToolBox(); + +private: + Ui::hpToolBox *ui; +}; + +#endif // HPTOOLBOX_H diff --git a/hptreeitem.cpp b/hptreeitem.cpp new file mode 100644 index 0000000..18eb6e2 --- /dev/null +++ b/hptreeitem.cpp @@ -0,0 +1,6 @@ +#include "hptreeitem.h" + +hptreeitem::hptreeitem() +{ + +} diff --git a/hptreeitem.h b/hptreeitem.h new file mode 100644 index 0000000..6cd090a --- /dev/null +++ b/hptreeitem.h @@ -0,0 +1,11 @@ +#ifndef HPTREEITEM_H +#define HPTREEITEM_H + + +class hptreeitem +{ +public: + hptreeitem(); +}; + +#endif // HPTREEITEM_H \ No newline at end of file diff --git a/hpusb.cpp b/hpusb.cpp new file mode 100644 index 0000000..171e00b --- /dev/null +++ b/hpusb.cpp @@ -0,0 +1,6 @@ +#include "hpusb.h" + +hpusb::hpusb() +{ + +} diff --git a/hpusb.h b/hpusb.h new file mode 100644 index 0000000..afad63f --- /dev/null +++ b/hpusb.h @@ -0,0 +1,11 @@ +#ifndef HPUSB_H +#define HPUSB_H + + +class hpusb +{ +public: + hpusb(); +}; + +#endif // HPUSB_H \ No newline at end of file diff --git a/icons/1_Prime_compact.primeskin b/icons/1_Prime_compact.primeskin new file mode 100644 index 0000000..7d9e56d --- /dev/null +++ b/icons/1_Prime_compact.primeskin @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + +
+ + + + +
+
+
+
+ + + + + + +
+ + + + +
+ + + + +
+ + +
+
+
+
+ + + + +
+ + +
+ + + + +
+ + + + +
+ + + + +
+
+
+
+ + + + +
+
+ + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+
+ + + + + \ No newline at end of file diff --git a/icons/2_Prime_compact_L.primeskin b/icons/2_Prime_compact_L.primeskin new file mode 100644 index 0000000..abc15f2 --- /dev/null +++ b/icons/2_Prime_compact_L.primeskin @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + +
+ + + + +
+
+
+
+ + + + + + +
+ + + + +
+ + + + +
+ + +
+
+
+
+ + + + +
+ + +
+ + + + +
+ + + + +
+ + + + +
+
+
+
+ + + + +
+
+ + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+
+ + + + + \ No newline at end of file diff --git a/icons/3_Prime_small.primeskin b/icons/3_Prime_small.primeskin new file mode 100644 index 0000000..470eabd --- /dev/null +++ b/icons/3_Prime_small.primeskin @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + +
+ + + + +
+
+
+
+ + + + + + +
+ + + + +
+ + + + +
+ + +
+
+
+
+ + + + +
+ + +
+ + + + +
+ + + + +
+ + + + +
+
+
+
+ + + + +
+
+ + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+
+ + + + + \ No newline at end of file diff --git a/icons/4_Prime_med.primeskin b/icons/4_Prime_med.primeskin new file mode 100644 index 0000000..8a24caa --- /dev/null +++ b/icons/4_Prime_med.primeskin @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + +
+ + + + +
+
+
+
+ + + + + + +
+ + + + +
+ + + + +
+ + +
+
+
+
+ + + + +
+ + +
+ + + + +
+ + + + +
+ + + + +
+
+
+
+ + + + +
+
+ + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+
+ + + + + \ No newline at end of file diff --git a/icons/5_Prime_large_L.primeskin b/icons/5_Prime_large_L.primeskin new file mode 100644 index 0000000..48e8ae4 --- /dev/null +++ b/icons/5_Prime_large_L.primeskin @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + + + + +
+ + + + +
+
+
+
+ + + + + + +
+ + + + +
+ + + + +
+ + +
+
+
+
+ + + + +
+ + +
+ + + + +
+ + + + +
+ + + + +
+
+
+
+ + + + +
+
+ + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+
+ + + + + \ No newline at end of file diff --git a/icons/about_16x16.png b/icons/about_16x16.png new file mode 100644 index 0000000..23270c0 Binary files /dev/null and b/icons/about_16x16.png differ diff --git a/icons/about_32x32.png b/icons/about_32x32.png new file mode 100644 index 0000000..0ff137c Binary files /dev/null and b/icons/about_32x32.png differ diff --git a/icons/accessories-calculator.png b/icons/accessories-calculator.png new file mode 100644 index 0000000..dcad514 Binary files /dev/null and b/icons/accessories-calculator.png differ diff --git a/icons/add_background_16x16.png b/icons/add_background_16x16.png new file mode 100644 index 0000000..f743371 Binary files /dev/null and b/icons/add_background_16x16.png differ diff --git a/icons/add_background_22x22.png b/icons/add_background_22x22.png new file mode 100644 index 0000000..65e0dcb Binary files /dev/null and b/icons/add_background_22x22.png differ diff --git a/icons/add_background_32x32.png b/icons/add_background_32x32.png new file mode 100644 index 0000000..2d955f7 Binary files /dev/null and b/icons/add_background_32x32.png differ diff --git a/icons/add_icon_16x16.png b/icons/add_icon_16x16.png new file mode 100644 index 0000000..526a976 Binary files /dev/null and b/icons/add_icon_16x16.png differ diff --git a/icons/add_icon_22x22.png b/icons/add_icon_22x22.png new file mode 100644 index 0000000..214afb1 Binary files /dev/null and b/icons/add_icon_22x22.png differ diff --git a/icons/add_icon_32x32.png b/icons/add_icon_32x32.png new file mode 100644 index 0000000..5770b9a Binary files /dev/null and b/icons/add_icon_32x32.png differ diff --git a/icons/add_new_16x16.png b/icons/add_new_16x16.png new file mode 100644 index 0000000..1bed2c1 Binary files /dev/null and b/icons/add_new_16x16.png differ diff --git a/icons/add_new_22x22.png b/icons/add_new_22x22.png new file mode 100644 index 0000000..b53ae2c Binary files /dev/null and b/icons/add_new_22x22.png differ diff --git a/icons/add_new_32x32.png b/icons/add_new_32x32.png new file mode 100644 index 0000000..845bf02 Binary files /dev/null and b/icons/add_new_32x32.png differ diff --git a/icons/apps_16x16.png b/icons/apps_16x16.png new file mode 100644 index 0000000..db6939a Binary files /dev/null and b/icons/apps_16x16.png differ diff --git a/icons/apps_32x32.png b/icons/apps_32x32.png new file mode 100644 index 0000000..ae14849 Binary files /dev/null and b/icons/apps_32x32.png differ diff --git a/icons/backup_16x16.png b/icons/backup_16x16.png new file mode 100644 index 0000000..0cb9097 Binary files /dev/null and b/icons/backup_16x16.png differ diff --git a/icons/backup_32x32.png b/icons/backup_32x32.png new file mode 100644 index 0000000..c8f402b Binary files /dev/null and b/icons/backup_32x32.png differ diff --git a/icons/calc_tree_16x16.png b/icons/calc_tree_16x16.png new file mode 100644 index 0000000..61544a8 Binary files /dev/null and b/icons/calc_tree_16x16.png differ diff --git a/icons/calc_tree_22x22.png b/icons/calc_tree_22x22.png new file mode 100644 index 0000000..225aca9 Binary files /dev/null and b/icons/calc_tree_22x22.png differ diff --git a/icons/calc_tree_32x32.png b/icons/calc_tree_32x32.png new file mode 100644 index 0000000..96651c1 Binary files /dev/null and b/icons/calc_tree_32x32.png differ diff --git a/icons/casFolder_16x16.png b/icons/casFolder_16x16.png new file mode 100644 index 0000000..46ee194 Binary files /dev/null and b/icons/casFolder_16x16.png differ diff --git a/icons/casFolder_32x32.png b/icons/casFolder_32x32.png new file mode 100644 index 0000000..f681d4f Binary files /dev/null and b/icons/casFolder_32x32.png differ diff --git a/icons/casVars_16x16.png b/icons/casVars_16x16.png new file mode 100644 index 0000000..eeb4208 Binary files /dev/null and b/icons/casVars_16x16.png differ diff --git a/icons/casVars_32x32.png b/icons/casVars_32x32.png new file mode 100644 index 0000000..60f7137 Binary files /dev/null and b/icons/casVars_32x32.png differ diff --git a/icons/chars_16x16.png b/icons/chars_16x16.png new file mode 100644 index 0000000..084fdc9 Binary files /dev/null and b/icons/chars_16x16.png differ diff --git a/icons/chars_32x32.png b/icons/chars_32x32.png new file mode 100644 index 0000000..10ee8a4 Binary files /dev/null and b/icons/chars_32x32.png differ diff --git a/icons/chat_16x16.png b/icons/chat_16x16.png new file mode 100644 index 0000000..4c2b8e4 Binary files /dev/null and b/icons/chat_16x16.png differ diff --git a/icons/chat_22x22.png b/icons/chat_22x22.png new file mode 100644 index 0000000..401301c Binary files /dev/null and b/icons/chat_22x22.png differ diff --git a/icons/chat_32x32.png b/icons/chat_32x32.png new file mode 100644 index 0000000..bb8edb1 Binary files /dev/null and b/icons/chat_32x32.png differ diff --git a/icons/check_update_16x16.png b/icons/check_update_16x16.png new file mode 100644 index 0000000..6eeda2d Binary files /dev/null and b/icons/check_update_16x16.png differ diff --git a/icons/check_update_32x32.png b/icons/check_update_32x32.png new file mode 100644 index 0000000..b871852 Binary files /dev/null and b/icons/check_update_32x32.png differ diff --git a/icons/clear_16x16.png b/icons/clear_16x16.png new file mode 100644 index 0000000..096cf90 Binary files /dev/null and b/icons/clear_16x16.png differ diff --git a/icons/clear_32x32.png b/icons/clear_32x32.png new file mode 100644 index 0000000..c7b907f Binary files /dev/null and b/icons/clear_32x32.png differ diff --git a/icons/clone_from_16x16.png b/icons/clone_from_16x16.png new file mode 100644 index 0000000..eb33938 Binary files /dev/null and b/icons/clone_from_16x16.png differ diff --git a/icons/clone_from_32x32.png b/icons/clone_from_32x32.png new file mode 100644 index 0000000..2415da4 Binary files /dev/null and b/icons/clone_from_32x32.png differ diff --git a/icons/clone_to_16x16.png b/icons/clone_to_16x16.png new file mode 100644 index 0000000..0d66942 Binary files /dev/null and b/icons/clone_to_16x16.png differ diff --git a/icons/clone_to_32x32.png b/icons/clone_to_32x32.png new file mode 100644 index 0000000..dbec66c Binary files /dev/null and b/icons/clone_to_32x32.png differ diff --git a/icons/complex_16x16.png b/icons/complex_16x16.png new file mode 100644 index 0000000..b2d4822 Binary files /dev/null and b/icons/complex_16x16.png differ diff --git a/icons/complex_32x32.png b/icons/complex_32x32.png new file mode 100644 index 0000000..6993e35 Binary files /dev/null and b/icons/complex_32x32.png differ diff --git a/icons/content_16x16.png b/icons/content_16x16.png new file mode 100644 index 0000000..0d8efd8 Binary files /dev/null and b/icons/content_16x16.png differ diff --git a/icons/content_22x22.png b/icons/content_22x22.png new file mode 100644 index 0000000..ed0da54 Binary files /dev/null and b/icons/content_22x22.png differ diff --git a/icons/content_32x32.png b/icons/content_32x32.png new file mode 100644 index 0000000..0045221 Binary files /dev/null and b/icons/content_32x32.png differ diff --git a/icons/copy_16x16.png b/icons/copy_16x16.png new file mode 100644 index 0000000..2d001bd Binary files /dev/null and b/icons/copy_16x16.png differ diff --git a/icons/copy_32x32.png b/icons/copy_32x32.png new file mode 100644 index 0000000..7e27ba5 Binary files /dev/null and b/icons/copy_32x32.png differ diff --git a/icons/cut_16x16.png b/icons/cut_16x16.png new file mode 100644 index 0000000..79d228e Binary files /dev/null and b/icons/cut_16x16.png differ diff --git a/icons/cut_32x32.png b/icons/cut_32x32.png new file mode 100644 index 0000000..4f5ca56 Binary files /dev/null and b/icons/cut_32x32.png differ diff --git a/icons/delete_16x16.png b/icons/delete_16x16.png new file mode 100644 index 0000000..9d0da2e Binary files /dev/null and b/icons/delete_16x16.png differ diff --git a/icons/delete_32x32.png b/icons/delete_32x32.png new file mode 100644 index 0000000..215e754 Binary files /dev/null and b/icons/delete_32x32.png differ diff --git a/icons/delete_col_16x16.png b/icons/delete_col_16x16.png new file mode 100644 index 0000000..5a58638 Binary files /dev/null and b/icons/delete_col_16x16.png differ diff --git a/icons/delete_col_32x32.png b/icons/delete_col_32x32.png new file mode 100644 index 0000000..c2829c6 Binary files /dev/null and b/icons/delete_col_32x32.png differ diff --git a/icons/delete_row_16x16.png b/icons/delete_row_16x16.png new file mode 100644 index 0000000..46b49a0 Binary files /dev/null and b/icons/delete_row_16x16.png differ diff --git a/icons/delete_row_32x32.png b/icons/delete_row_32x32.png new file mode 100644 index 0000000..f0cff02 Binary files /dev/null and b/icons/delete_row_32x32.png differ diff --git a/icons/exam_mode_16x16.png b/icons/exam_mode_16x16.png new file mode 100644 index 0000000..1830ba0 Binary files /dev/null and b/icons/exam_mode_16x16.png differ diff --git a/icons/exam_mode_32x32.png b/icons/exam_mode_32x32.png new file mode 100644 index 0000000..df5044d Binary files /dev/null and b/icons/exam_mode_32x32.png differ diff --git a/icons/fileFolder_16x16.png b/icons/fileFolder_16x16.png new file mode 100644 index 0000000..f08b224 Binary files /dev/null and b/icons/fileFolder_16x16.png differ diff --git a/icons/fileFolder_32x32.png b/icons/fileFolder_32x32.png new file mode 100644 index 0000000..7bb7ca2 Binary files /dev/null and b/icons/fileFolder_32x32.png differ diff --git a/icons/file_16x16.png b/icons/file_16x16.png new file mode 100644 index 0000000..3b565ea Binary files /dev/null and b/icons/file_16x16.png differ diff --git a/icons/file_32x32.png b/icons/file_32x32.png new file mode 100644 index 0000000..5a03ae5 Binary files /dev/null and b/icons/file_32x32.png differ diff --git a/icons/firmware_16x16.png b/icons/firmware_16x16.png new file mode 100644 index 0000000..2884650 Binary files /dev/null and b/icons/firmware_16x16.png differ diff --git a/icons/firmware_32x32.png b/icons/firmware_32x32.png new file mode 100644 index 0000000..caa0220 Binary files /dev/null and b/icons/firmware_32x32.png differ diff --git a/icons/help_16x16.png b/icons/help_16x16.png new file mode 100644 index 0000000..99d8582 Binary files /dev/null and b/icons/help_16x16.png differ diff --git a/icons/help_32x32.png b/icons/help_32x32.png new file mode 100644 index 0000000..14efe93 Binary files /dev/null and b/icons/help_32x32.png differ diff --git a/icons/insert_col_16x16.png b/icons/insert_col_16x16.png new file mode 100644 index 0000000..73c13e0 Binary files /dev/null and b/icons/insert_col_16x16.png differ diff --git a/icons/insert_col_32x32.png b/icons/insert_col_32x32.png new file mode 100644 index 0000000..2fd49e6 Binary files /dev/null and b/icons/insert_col_32x32.png differ diff --git a/icons/insert_row_16x16.png b/icons/insert_row_16x16.png new file mode 100644 index 0000000..f6facb4 Binary files /dev/null and b/icons/insert_row_16x16.png differ diff --git a/icons/insert_row_32x32.png b/icons/insert_row_32x32.png new file mode 100644 index 0000000..00b81df Binary files /dev/null and b/icons/insert_row_32x32.png differ diff --git a/icons/internet_16x16.png b/icons/internet_16x16.png new file mode 100644 index 0000000..9d81ef3 Binary files /dev/null and b/icons/internet_16x16.png differ diff --git a/icons/internet_32x32.png b/icons/internet_32x32.png new file mode 100644 index 0000000..7bf0446 Binary files /dev/null and b/icons/internet_32x32.png differ diff --git a/icons/language_16x16.png b/icons/language_16x16.png new file mode 100644 index 0000000..dba77a6 Binary files /dev/null and b/icons/language_16x16.png differ diff --git a/icons/language_32x32.png b/icons/language_32x32.png new file mode 100644 index 0000000..3823f90 Binary files /dev/null and b/icons/language_32x32.png differ diff --git a/icons/list_16x16.png b/icons/list_16x16.png new file mode 100644 index 0000000..cf14170 Binary files /dev/null and b/icons/list_16x16.png differ diff --git a/icons/list_32x32.png b/icons/list_32x32.png new file mode 100644 index 0000000..74beba9 Binary files /dev/null and b/icons/list_32x32.png differ diff --git a/icons/monitor_16x16.png b/icons/monitor_16x16.png new file mode 100644 index 0000000..6eee5c6 Binary files /dev/null and b/icons/monitor_16x16.png differ diff --git a/icons/monitor_22x22.png b/icons/monitor_22x22.png new file mode 100644 index 0000000..d877046 Binary files /dev/null and b/icons/monitor_22x22.png differ diff --git a/icons/monitor_32x32.png b/icons/monitor_32x32.png new file mode 100644 index 0000000..ca1a115 Binary files /dev/null and b/icons/monitor_32x32.png differ diff --git a/icons/new_folder_16x16.png b/icons/new_folder_16x16.png new file mode 100644 index 0000000..13699fc Binary files /dev/null and b/icons/new_folder_16x16.png differ diff --git a/icons/new_folder_22x22.png b/icons/new_folder_22x22.png new file mode 100644 index 0000000..498e5c9 Binary files /dev/null and b/icons/new_folder_22x22.png differ diff --git a/icons/new_folder_32x32.png b/icons/new_folder_32x32.png new file mode 100644 index 0000000..5e3319f Binary files /dev/null and b/icons/new_folder_32x32.png differ diff --git a/icons/note_16x16.png b/icons/note_16x16.png new file mode 100644 index 0000000..15b0488 Binary files /dev/null and b/icons/note_16x16.png differ diff --git a/icons/note_32x32.png b/icons/note_32x32.png new file mode 100644 index 0000000..6398f6e Binary files /dev/null and b/icons/note_32x32.png differ diff --git a/icons/open_16x16.png b/icons/open_16x16.png new file mode 100644 index 0000000..b273580 Binary files /dev/null and b/icons/open_16x16.png differ diff --git a/icons/open_32x32.png b/icons/open_32x32.png new file mode 100644 index 0000000..8c9ecec Binary files /dev/null and b/icons/open_32x32.png differ diff --git a/icons/paste_16x16.png b/icons/paste_16x16.png new file mode 100644 index 0000000..9e382e6 Binary files /dev/null and b/icons/paste_16x16.png differ diff --git a/icons/paste_32x32.png b/icons/paste_32x32.png new file mode 100644 index 0000000..9e7d0d1 Binary files /dev/null and b/icons/paste_32x32.png differ diff --git a/icons/poll_16x16.png b/icons/poll_16x16.png new file mode 100644 index 0000000..265cf0f Binary files /dev/null and b/icons/poll_16x16.png differ diff --git a/icons/poll_32x32.png b/icons/poll_32x32.png new file mode 100644 index 0000000..56890fc Binary files /dev/null and b/icons/poll_32x32.png differ diff --git a/icons/preferences_16x16.png b/icons/preferences_16x16.png new file mode 100644 index 0000000..d00968e Binary files /dev/null and b/icons/preferences_16x16.png differ diff --git a/icons/preferences_32x32.png b/icons/preferences_32x32.png new file mode 100644 index 0000000..e70d54f Binary files /dev/null and b/icons/preferences_32x32.png differ diff --git a/icons/proctor_16x16.png b/icons/proctor_16x16.png new file mode 100644 index 0000000..6114a19 Binary files /dev/null and b/icons/proctor_16x16.png differ diff --git a/icons/proctor_22x22.png b/icons/proctor_22x22.png new file mode 100644 index 0000000..9976e34 Binary files /dev/null and b/icons/proctor_22x22.png differ diff --git a/icons/proctor_32x32.png b/icons/proctor_32x32.png new file mode 100644 index 0000000..f401697 Binary files /dev/null and b/icons/proctor_32x32.png differ diff --git a/icons/program_16x16.png b/icons/program_16x16.png new file mode 100644 index 0000000..57e3053 Binary files /dev/null and b/icons/program_16x16.png differ diff --git a/icons/program_32x32.png b/icons/program_32x32.png new file mode 100644 index 0000000..5c45157 Binary files /dev/null and b/icons/program_32x32.png differ diff --git a/icons/project_16x16.png b/icons/project_16x16.png new file mode 100644 index 0000000..6f12a59 Binary files /dev/null and b/icons/project_16x16.png differ diff --git a/icons/project_32x32.png b/icons/project_32x32.png new file mode 100644 index 0000000..f5672ea Binary files /dev/null and b/icons/project_32x32.png differ diff --git a/icons/properties_16x16.png b/icons/properties_16x16.png new file mode 100644 index 0000000..7485352 Binary files /dev/null and b/icons/properties_16x16.png differ diff --git a/icons/properties_32x32.png b/icons/properties_32x32.png new file mode 100644 index 0000000..fb0b25e Binary files /dev/null and b/icons/properties_32x32.png differ diff --git a/icons/real_16x16.png b/icons/real_16x16.png new file mode 100644 index 0000000..c23cf48 Binary files /dev/null and b/icons/real_16x16.png differ diff --git a/icons/real_32x32.png b/icons/real_32x32.png new file mode 100644 index 0000000..545aa06 Binary files /dev/null and b/icons/real_32x32.png differ diff --git a/icons/refresh_16x16.png b/icons/refresh_16x16.png new file mode 100644 index 0000000..93c6fee Binary files /dev/null and b/icons/refresh_16x16.png differ diff --git a/icons/refresh_32x32.png b/icons/refresh_32x32.png new file mode 100644 index 0000000..1109b87 Binary files /dev/null and b/icons/refresh_32x32.png differ diff --git a/icons/rename_16x16.png b/icons/rename_16x16.png new file mode 100644 index 0000000..e092b5c Binary files /dev/null and b/icons/rename_16x16.png differ diff --git a/icons/rename_32x32.png b/icons/rename_32x32.png new file mode 100644 index 0000000..9615935 Binary files /dev/null and b/icons/rename_32x32.png differ diff --git a/icons/reset_16x16.png b/icons/reset_16x16.png new file mode 100644 index 0000000..61daac2 Binary files /dev/null and b/icons/reset_16x16.png differ diff --git a/icons/reset_32x32.png b/icons/reset_32x32.png new file mode 100644 index 0000000..2304d95 Binary files /dev/null and b/icons/reset_32x32.png differ diff --git a/icons/restore_16x16.png b/icons/restore_16x16.png new file mode 100644 index 0000000..bfbc8fa Binary files /dev/null and b/icons/restore_16x16.png differ diff --git a/icons/restore_32x32.png b/icons/restore_32x32.png new file mode 100644 index 0000000..9f4a562 Binary files /dev/null and b/icons/restore_32x32.png differ diff --git a/icons/results_16x16.png b/icons/results_16x16.png new file mode 100644 index 0000000..8776eab Binary files /dev/null and b/icons/results_16x16.png differ diff --git a/icons/results_32x32.png b/icons/results_32x32.png new file mode 100644 index 0000000..59c8682 Binary files /dev/null and b/icons/results_32x32.png differ diff --git a/icons/save_16x16.png b/icons/save_16x16.png new file mode 100644 index 0000000..ae37f2a Binary files /dev/null and b/icons/save_16x16.png differ diff --git a/icons/save_22x22.png b/icons/save_22x22.png new file mode 100644 index 0000000..ca89b5e Binary files /dev/null and b/icons/save_22x22.png differ diff --git a/icons/save_32x32.png b/icons/save_32x32.png new file mode 100644 index 0000000..8e8699e Binary files /dev/null and b/icons/save_32x32.png differ diff --git a/icons/save_all_16x16.png b/icons/save_all_16x16.png new file mode 100644 index 0000000..5a9d174 Binary files /dev/null and b/icons/save_all_16x16.png differ diff --git a/icons/save_all_22x22.png b/icons/save_all_22x22.png new file mode 100644 index 0000000..e8bc378 Binary files /dev/null and b/icons/save_all_22x22.png differ diff --git a/icons/save_all_32x32.png b/icons/save_all_32x32.png new file mode 100644 index 0000000..17c94b8 Binary files /dev/null and b/icons/save_all_32x32.png differ diff --git a/icons/save_as_16x16.png b/icons/save_as_16x16.png new file mode 100644 index 0000000..172e365 Binary files /dev/null and b/icons/save_as_16x16.png differ diff --git a/icons/save_as_32x32.png b/icons/save_as_32x32.png new file mode 100644 index 0000000..d298c88 Binary files /dev/null and b/icons/save_as_32x32.png differ diff --git a/icons/screenshot_16x16.png b/icons/screenshot_16x16.png new file mode 100644 index 0000000..9c3d939 Binary files /dev/null and b/icons/screenshot_16x16.png differ diff --git a/icons/screenshot_32x32.png b/icons/screenshot_32x32.png new file mode 100644 index 0000000..9faae66 Binary files /dev/null and b/icons/screenshot_32x32.png differ diff --git a/icons/send_16x16.png b/icons/send_16x16.png new file mode 100644 index 0000000..2894a5c Binary files /dev/null and b/icons/send_16x16.png differ diff --git a/icons/send_32x32.png b/icons/send_32x32.png new file mode 100644 index 0000000..5f0d720 Binary files /dev/null and b/icons/send_32x32.png differ diff --git a/icons/start_16x16.png b/icons/start_16x16.png new file mode 100644 index 0000000..87aadf7 Binary files /dev/null and b/icons/start_16x16.png differ diff --git a/icons/start_32x32.png b/icons/start_32x32.png new file mode 100644 index 0000000..b26aa47 Binary files /dev/null and b/icons/start_32x32.png differ diff --git a/icons/stop_16x16.png b/icons/stop_16x16.png new file mode 100644 index 0000000..11c4b7f Binary files /dev/null and b/icons/stop_16x16.png differ diff --git a/icons/stop_32x32.png b/icons/stop_32x32.png new file mode 100644 index 0000000..7350894 Binary files /dev/null and b/icons/stop_32x32.png differ diff --git a/icons/table_16x16.png b/icons/table_16x16.png new file mode 100644 index 0000000..856ed06 Binary files /dev/null and b/icons/table_16x16.png differ diff --git a/icons/table_32x32.png b/icons/table_32x32.png new file mode 100644 index 0000000..3814a4d Binary files /dev/null and b/icons/table_32x32.png differ diff --git a/icons/varFolder_16x16.png b/icons/varFolder_16x16.png new file mode 100644 index 0000000..f4179e8 Binary files /dev/null and b/icons/varFolder_16x16.png differ diff --git a/icons/varFolder_32x32.png b/icons/varFolder_32x32.png new file mode 100644 index 0000000..5a8f6d7 Binary files /dev/null and b/icons/varFolder_32x32.png differ diff --git a/icons/vars_16x16.png b/icons/vars_16x16.png new file mode 100644 index 0000000..5870ae5 Binary files /dev/null and b/icons/vars_16x16.png differ diff --git a/icons/vars_32x32.png b/icons/vars_32x32.png new file mode 100644 index 0000000..fffa271 Binary files /dev/null and b/icons/vars_32x32.png differ diff --git a/input.txt b/input.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/input.txt @@ -0,0 +1 @@ + diff --git a/libhpcalcs/AUTHORS b/libhpcalcs/AUTHORS new file mode 100644 index 0000000..b9447cf --- /dev/null +++ b/libhpcalcs/AUTHORS @@ -0,0 +1,8 @@ +hplibs +====== +Lionel Debroux + +Code patterns and snippets borrowed from libti*/tilp: +Romain Liévin +Benjamin Moody +... and other contributors listed in the AUTHORS files of libti* & tilp. diff --git a/libhpcalcs/COPYING b/libhpcalcs/COPYING new file mode 100644 index 0000000..f90922e --- /dev/null +++ b/libhpcalcs/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/libhpcalcs/ChangeLog b/libhpcalcs/ChangeLog new file mode 100644 index 0000000..5a76bbd --- /dev/null +++ b/libhpcalcs/ChangeLog @@ -0,0 +1,3 @@ +Log of changes (libhpcalcs): + + - Initial version. diff --git a/libhpcalcs/NEWS b/libhpcalcs/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/libhpcalcs/README b/libhpcalcs/README new file mode 100644 index 0000000..0971758 --- /dev/null +++ b/libhpcalcs/README @@ -0,0 +1,315 @@ +hplp: code for communicating with recent HP calculators +======================================================= + +hplp (still entirely in libhpcalcs for now) is the beginning of a toolkit for +two-way communications with HP Prime calculators. + +See below for detailed build instructions. Note that +the install_hplp.sh script provided alongside this README +( https://raw.github.com/debrouxl/hplp/master/install_hplp.sh ) +automates part of the build process. + + +Status (2014/06/03) +------------------- +The code base does: +* work on Windows, Linux and MacOS X; +* support communication with a single Prime calculator connected to the + computer. The communication is known to work with the following firmware + versions, but might not work with other older or newer versions, if HP + performs backwards-incompatible changes in the protocol (like TI does): + * "SDKV0.30" firmware version from mid-August 2013; + * "SDKV0.32" build 5447 firmware version from late November 2013; + * partial success with the V0.031.6030 / V0.032.6030 build 6030 firmware + versions published late May 2013. +* implement 10 operations (without _known_ bugs): + * ready check; + * get calculator information; + * set date and time; + * receive screenshot; + * send file (for now, the leading metadata of *.hpprgm, if any, needs to be + stripped manually); + * receive file; + * receive backup; + * send key(s) (remote control); + * send chat; + * receive chat; +* provide a terminal-based UI: the test program "test_hpcalcs". + +The code base doesn't: +* perform color conversion on PNG screenshots (libhpcalcs should use libpng to + uncompress the files, mangle pixels, and recompress to PNG); +* provide a user-friendly GUI for the above, but a GUI can definitely build + upon the library easily enough; +* implement _proper_ conversion from UTF-16 LE to other charsets on its own: + that's a task for libicu, Qt or other libraries. + + +Goals +----- +Laying the groundwork for GUIs dealing with two-way communication with HP +Prime calculators, and possibly 39gII (Prime and 39gII are similar), using +USB HID class, and possibly later fake MSD for firmware upgrades. + + +Non-goals +--------- +As far as I'm concerned, working _by myself_ on: +* duplicating / replacing code targeting older, non-USB HID-based HP + calculators; +* a GUI comparable to HP's Connectivity Kit. However, other people should + obviously do it, in order to make the software much more usable ! + + +Build process summary +--------------------- +As mentioned above, the repository contains an script for automating the +part of the build strictly related to libhpcalcs / hplp: install_hplp.sh . + +The build process is that of pretty much any autotools-based piece of +software: +$ autoreconf -i -f +$ ./configure +$ ./make check +# make install + +The terminal-based test program is in tests/test_hpcalcs. + +For now, the main external dependency of libhpcalcs is HIDAPI: +https://github.com/signal11/hidapi.git +Unless your Linux distro packages it (few do), you need to compile and +install it yourself (it is also an autotools-based project: configure, +make, make install). + + +Detailed build & configuration process for Debian, Ubuntu, Mint and derivatives +(courtesy of Jonathan Cameron) +------------------------------------------------------------------------------- + +1. Install build dependencies (packages required for building libhpcalcs). +As root (with root shell, or sudo) +# (sudo) apt-get install build-essential git autoconf automake autopoint libtool gettext xdg-utils libpng-dev libudev-dev libusb-1.0-0-dev autotools-dev + +2. Install hidapi: + +$ mkdir -p $HOME/lpg # or anywhere else you see fit +$ cd $HOME/lpg +$ git clone https://github.com/signal11/hidapi.git hidapi +$ cd hidapi + +Follow the directions from the README.txt file: + +$ ./bootstrap +$ ./configure --prefix=/usr +$ make + +As root (with root shell, or sudo): +# (sudo) make install <----- as root, or using sudo + +3. Install libhpcalcs + +Download +https://raw.github.com/debrouxl/hplp/master/install_hplp.sh +and copy it to, for instance, $HOME/hplp + +$ cd $HOME/lpg +$ chmod +x install_hplp.sh +# (sudo) ./install_hplp.sh + +4. Test hplp + +As root, verify that you can run test_hpcalcs. +Plug in your HP Prime to the computer and turn it on. +Wait about 10 seconds and then run: + +$ $HOME/lpg/hplp/libhpcalcs/tests/test_hpcalcs + +You should see the menu of possible operations. +If you do, hplp is working and you are successfully communicating with your Prime. + +5. Set up for normal users to access the Prime with the test software. + + a. If you are on your own isolated computer (e.g, laptop), + then add the following udev rules to the new file + /etc/udev/rules.d/82-hp-prime.rules : + + # HP Prime Calculator + SUBSYSTEM=="usb", ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0441", MODE="0666" + KERNEL=="hidraw*", ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0441", MODE="0666" + + Note that anyone on your system will be able to access your Prime with + the hplp software. + + If you are on a shared system and you want to avoid anyone accessing the + device but you, do this instead: + + # HP Prime Calculator + SUBSYSTEM=="usb", ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0441", ACTION=="add", GROUP="dialout", MODE="0664" + KERNEL=="hidraw*", ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0441", ACTION=="add", GROUP="dialout", MODE="0664" + + and add yourself to the 'dialout' group. You may need to switch to + the new group for this to work (eg: newgrp dialout). + + To activate the new udev rule, turn off your HP Prime, turn it back on, + and wait for about 10 seconds. Then, check the permissions for the device + (in /dev/hidraw? and /dev/usb/hiddev?). + + +NOTES: + * technically, compilation doesn't require being root, only the 'make install' + commands for hidapi and libhpcalcs (embedded into install_hplp.sh) require + root (and even then, only if installing to /usr or some root-only location). + install_hplp.sh cannot use sudo on its own, as it's not necessarily + configured by default. + * in the above directions, the source location to be $HOME/lpg. You may prefer + some other location, just replace $HOME/lpg by your location. + * the install prefix is forced to /usr, so that you don't have to adjust the + LD_LIBRARY_PATH environment variable, or add a line in /etc/ld.so.conf, or + add a file in /etc/ld.so.conf.d. + The install prefix is controlled by using the --prefix option to configure, + for hidapi and within install_hplp.sh. + + +Technical notes +--------------- +The code leverages HIDAPI, and it was strongly inspired by the time-proven +concepts and APIs of the libti* family, which I (Lionel Debroux) am the +current maintainer of. +The GPL'ed libti* family ( https://github.com/debrouxl/tilibs ) forms the +back-end for TILP, TIEmu, TilEm and titools (mainly), and contains the only +third-party portable FLOSS code with two-way communication support for all +three series of TI-Z80, TI-68k and TI-Nspire graphing calculators. +Putting together framework strongly inspired by libti* clearly took some work, +but having such a foundation saves time in the longer term. IOW, it's worth +the apparent complexity. + +Obviously, until the calculator's protocol is better documented, the API +will change in backwards-incompatible manners (for instance, the output +parameters of check ready and get infos operations). + + +TODO list +--------- +* ... hopefully attract _code_ contributors who have more free time than I do; +* a GUI, but I won't be the one doing it. + Nowadays, Qt is the main choice for a portable, good-looking, fast UI + toolkit (for native code programs). GTK+ used to be a better choice wrt. + portability, but that was years ago, and in 2013-2015, a number of + applications and desktop environments are switching from GTK+ to Qt. + UIs based on Web technologies are another option, Qt provides support for + those (QtWebkit / QtWebEngine) as well. +* strip out leading program metadata, if any, from .hpprgm files, like the + UTF-16LE BOM is already stripped. + Implementation notes: + * in a loop, attempt to read 4 bytes containing size, and seek forward of + that many bytes. If this leads the offset beyond EOF, break out. +* add some form of packet parsing + validation API, which can be used for + both internal sanity checking and packet dissection; +* add 39gII support, probably, as the Prime is similar to the 39gII. That's + where the usefulness of the cables / calcs separation and cables generic + API will become most obvious. + Implementation notes: + * move the upper layer from prime_cmd into a new file called by both + prime_cmd and the new file (like e.g. dusb_cmd in libticalcs). + * the 39gII has 00 00 CRC. +* modify the way recv_backup works for more reliability. + Implementation notes: + * recv_backup should attempt to receive as much data as the calculator sends, + and then split the received data. The main heuristic would be to assume + that some packets were lost, and traverse backwards the contents of the + current file to find a (00) F7 01 xx xx xx xx packet ? While this could + fail in some circumstances, it should usually salvage more data. + * recv_file shall probably be refactored as well; + * Marcus Von Cube reported that when receiving a backup fails, the test + program crashes: +" +hpcalcs INFO: prime_send_data: send remaining failed +hpcalcs ERROR: calc_prime_recv_backup: s_recv_backup failed +hpcalcs ERROR: hpcalcs_calc_recv_backup: recv_backup failed +hpfiles INFO: Displaying var entry 83EC8B55 +hpfiles INFO: Name: +" +* implement screenshot color conversion, with libpng; +* add progress feedback functionality, improved from libti*: the libti* + implementation is too complex. + Implementation notes: + * can information for current chunk of the transfer + information for the + transfer as a whole be passed through arguments of a single callback. +* add port number functionality, known from libticables, in the API. That + will enable passthrough mode for communication between real and/or + emulated calculators; +* fill in torture test; +* add two APIs for dynamically building NULL-terminated const char * arrays + from the two first columns of typesprime.c::PRIME_CONST. +* somehow gain better knowledge of the protocol, so as to be able to... +* ... add more operations and data structures. +* add dissectors and session logs, improved from libticables. + Design goals: + * make it possible to trace packet flow direction; + * make it possible to validate (sanity check) packets , to begin with... + Implementation notes: + * new APIs for registering and unregistering (multiple) callbacks; + * call the registered callbacks upon packet send and packet receive; + * leverage the packet parsing / validation code. +* add support for Prime in fake MSD mode, for firmware upgrades ? I've + already partially analyzed the protocol and published my notes at + http://tiplanet.org/hpwiki/index.php?title=HP_Prime/Linking_Protocol + but I'm not really confident about it ;) + Need to find a library for MSD. libusb does not recommend using it + in MSD mode. +* certainly more... at least, if users and programmers think the software + fits a purpose :-) + + +License +------- +Copyright (C) 2013-2015 Lionel Debroux + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Changelog +--------- +2013/11/03 - 2013/12/30: improve logging, create install_hplp.sh, improve +error passing, fix bugs reported by more beta-testers, add more operations. +2013/10/22 - 2013/11/03: Created autotools-based project and test client; +vastly expand the code, to the point it becomes releasable (if not really +usable). First public announcement (limited scope). +2013/10/21: Split into multiple files, but still piggybacking hidtest.cpp. +2013/10/20: First public PoC. +2013/10/19: Project started. + + +Credits (demoscene style) +------------------------- +* _many_ thanks to Xavier "critor" Andrani for testing many program versions + on his real Prime and providing many USB packet dumps (which I analyzed + with Wireshark) and terminal output sessions; +* many thanks to Marcus Von Cube for providing USB packet dumps for the 39gII, + which show that it's quite similar to the Prime; +* thanks to Jonathan Cameron for writing a more detailed build procedure for + Debian and derivatives; +* thanks to other beta-testers who reported bugs on TI-Planet and MoHPC: + * with the Prime: persalteas (Linux), wawachief (Linux & MacOS X), DJ + Omnimaga (Windows), Adriweb (MacOS X & Windows), Jonathan Cameron (Linux), + Cristian Arezzini (Linux), LarsF (MacOS X), Egan Ford (MacOS X); + * with the 39gII: Marcus Von Cube; +* greetings to the other TI-Planet ( http://tiplanet.org/ ) admins; +* greetings to the HP Prime developer team at HP: some of its members spend + time attending user message boards and interacting with users and programmers, + even in communities traditionally interested in TI calcs (Omnimaga, Cemetech, + TI-Planet), which is a win-win move for both HP and its users; +* fuck TI EdTech management imposing a closed-minded, lose-lose stance on the + Nspire platform, despite repeated community input since 2007. diff --git a/libhpcalcs/include/error.h b/libhpcalcs/include/error.h new file mode 100644 index 0000000..5d5ebd2 --- /dev/null +++ b/libhpcalcs/include/error.h @@ -0,0 +1,71 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file error.h Files / cables / calcs: Error IDs. + */ + +#ifndef __HPLIBS_CALCS_ERROR_H__ +#define __HPLIBS_CALCS_ERROR_H__ + +typedef enum { + ERR_HPLIBS_GENERIC_FIRST = 0, + ERR_SUCCESS = 0, // Must be equal to ERR_HPLIBS_GENERIC_FIRST + ERR_MALLOC, + ERR_INVALID_HANDLE, + ERR_INVALID_PARAMETER, + ERR_INVALID_MODEL, + ERR_LIBRARY_INIT, + ERR_LIBRARY_EXIT, + ERR_LIBRARY_CONFIG_VERSION, + ERR_HPLIBS_GENERIC_LAST = 127, + + ERR_FILE_FIRST = 128, + ERR_FILE_FILENAME = 128, + ERR_FILE_LAST = 255, + + ERR_CABLE_FIRST = 256, + ERR_CABLE_NOT_OPEN = 256, + ERR_CABLE_OPEN, + ERR_CABLE_BUSY, + ERR_CABLE_WRITE_ERROR, + ERR_CABLE_READ_ERROR, + ERR_CABLE_INVALID_FNCTS, + ERR_CABLE_PROBE_FAILED, + ERR_CABLE_LAST = 383, + + ERR_CALC_FIRST = 384, + ERR_CALC_NO_CABLE = 384, + ERR_CALC_CABLE_NOT_OPEN, + ERR_CALC_BUSY, + ERR_CALC_INVALID_FNCTS, + ERR_CALC_PACKET_FORMAT, + ERR_CALC_SPLIT_TIMESTAMP, + ERR_CALC_PROBE_FAILED, + ERR_CALC_LAST = 511, + + ERR_OPER_FIRST = 512, + ERR_OPER_LAST = 639 +} hplibs_error; + +#endif diff --git a/libhpcalcs/include/export.h b/libhpcalcs/include/export.h new file mode 100644 index 0000000..2505dbb --- /dev/null +++ b/libhpcalcs/include/export.h @@ -0,0 +1,91 @@ +/* + * libhpfiles, libhpcables, libhpcalcs - hand-helds support library + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file export.h Stuff for function export and calling convention. + */ + +#ifndef __HPCALCS_EXPORT__ +#define __HPCALCS_EXPORT__ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Calling convention: default +#define HPCALL + +// Symbols export +#if defined(HAVE_FVISIBILITY) // GCC 4.0 has introduced the -fvisibility flag (similar to declspec) +#define HPEXPORT __attribute__ ((visibility("default"))) + +#elif defined(__WIN32__) +# if defined(_MSC_VER) // MSVC 5.0 mini +# if defined(HPCALCS_EXPORTS) +# define HPEXPORT __declspec(dllexport) +# else +# define HPEXPORT __declspec(dllimport) +# endif + +# elif defined(__MINGW32__) // MinGW - GCC for Windows, (c) 2002 Kevin Kofler +# if defined(HPCALCS_EXPORTS) // defined by the configure script +# define HPEXPORT __declspec(dllexport) +# else +# define HPEXPORT __declspec(dllimport) +# endif +# endif + +#else +# define HPEXPORT // default +#endif + +#ifdef __cplusplus +} +#endif + +// Symbols deprecation +#ifndef HPLIBS_DEPRECATED +# ifdef __GNUC__ +# if (__GNUC__>3) || (__GNUC__==3 && __GNUC_MINOR__>=3) +# define HPLIBS_DEPRECATED __attribute__((deprecated)) +# else /* not GCC >= 3.3 */ +# define HPLIBS_DEPRECATED +# endif /* GCC >= 3.3 */ +# else /* not __GNUC__ */ +# ifdef _MSC_VER +# if _MSC_VER >= 1300 +# define HPLIBS_DEPRECATED __declspec(deprecated) +# else /* not _MSC_VER >= 1300 */ +# define HPLIBS_DEPRECATED +# endif /* _MSC_VER >= 1300 */ +# else /* not _MSC_VER */ +# define HPLIBS_DEPRECATED +# endif /* _MSC_VER */ +# endif /* __GNUC__ */ +#endif /* HPLIBS_DEPRECATED */ + +#endif diff --git a/libhpcalcs/include/filetypes.h b/libhpcalcs/include/filetypes.h new file mode 100644 index 0000000..ddfd14c --- /dev/null +++ b/libhpcalcs/include/filetypes.h @@ -0,0 +1,35 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file filetypes.h Files: Umbrella header for file types. + */ + +#ifndef __HPLIBS_FILES_FILETYPES_H__ +#define __HPLIBS_FILES_FILETYPES_H__ + +#include "typesprime.h" + +#define HPLIBS_FILE_TYPE_UNKNOWN (0xFF) + +#endif diff --git a/libhpcalcs/include/gettext.h b/libhpcalcs/include/gettext.h new file mode 100644 index 0000000..1564ac7 --- /dev/null +++ b/libhpcalcs/include/gettext.h @@ -0,0 +1,60 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file gettext.h Files / cables / calcs: internationalization (i18n) stuff. + */ + +#ifndef HPLIBS_GETTEXT_H +#define HPLIBS_GETTEXT_H + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +#warning NLS disabled +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + +#endif diff --git a/libhpcalcs/include/hpcables.h b/libhpcalcs/include/hpcables.h new file mode 100644 index 0000000..922477c --- /dev/null +++ b/libhpcalcs/include/hpcables.h @@ -0,0 +1,249 @@ +/* + * libhpcables: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpcables.h Cables: base part. + */ + +#ifndef __HPLIBS_CABLES_H__ +#define __HPLIBS_CABLES_H__ + +#include +#include + +#include "hplibs.h" + +//! Opaque type for internal _cable_fncts. +typedef struct _cable_fncts cable_fncts; +//! Opaque type for internal _cable_handle. +typedef struct _cable_handle cable_handle; + +//! Internal structure containing information about the cable, and function pointers. +struct _cable_fncts { + cable_model model; + const char * name; + const char * description; + int (*probe) (cable_handle * handle); + int (*open) (cable_handle * handle); + int (*close) (cable_handle * handle); + int (*set_read_timeout) (cable_handle * handle, int read_timeout); + int (*send) (cable_handle * handle, uint8_t * data, uint32_t len); + int (*recv) (cable_handle * handle, uint8_t ** data, uint32_t * len); +}; + +//! Internal structure containing state about the cable, returned and passed around by the user. +struct _cable_handle { + cable_model model; + void * handle; + const cable_fncts * fncts; + int read_timeout; + int open; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. + int busy; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. +}; + + +//! Structure passed to \a hpcables_init, contains e.g. callbacks for logging and memory allocation. +typedef struct { + unsigned int version; ///< Config version number. + void (*log_callback)(const char *format, va_list args); ///< Callback function for receiving logging output. + hplibs_malloc_funcs * alloc_funcs; ///< Function pointers used for dynamic memory allocation. If NULL, the library defaults to malloc(), calloc(), realloc(), free(). +} hpcables_config; + +//! Latest revision of the \a hpcables_config struct layout supported by this version of the library. +#define HPCABLES_CONFIG_VERSION (1) + + +typedef enum { + PACKET_DIRECTION_NONE = 0, + PACKET_DIRECTION_SEND, + PACKET_DIRECTION_RECV +} CablePacketDirection; + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initializes library internals. Must be called before any other libhpcables function. + * \param config pointer to struct containing e.g. callbacks passed to the library. + * \return Whether the initialization succeeded. + * \note the contents of alloc_funcs are copied. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpcables_init(hpcables_config * config); +/** + * \brief Tears down library internals. No other libhpcables function can be called after this one. + * \return Whether the teardown succeeded. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpcables_exit(void); + +/** + * \brief Returns the library version string. + * \return The library version string, usually under the form "X.Y.Z". + **/ +HPEXPORT const char* HPCALL hpcables_version_get(void); + +/** + * \brief Returns the cables supported by the current build of the library. + * \return An integer containing a binary OR of (1 << CABLE_*) values, where CABLE_* values are defined in enum \a cable_model. + **/ +HPEXPORT uint32_t HPCALL hpcables_supported_cables(void); + +/** + * \brief Gets the error message if the error was produced by this library + * \param number the error number (from internal error.h) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * \note the string is allocated with malloc(), therefore it must be freed with free(). + * \return 0 if the error was produced by this library, otherwise the error number (for propagation). + **/ +HPEXPORT int HPCALL hpcables_error_get(int number, char **message); + +/** + * \brief Sets the callback function used by the library for logging + * \param log_callback function pointer + */ +HPEXPORT void HPCALL hpcables_log_set_callback(void (*log_callback)(const char *format, va_list args)); +/** + * \brief Sets the log level of the library, for controlling how much logging output is produced. + * \param log_level log level (from hplibs.h) + * \return the previous log level + */ +HPEXPORT hplibs_logging_level HPCALL hpcables_log_set_level(hplibs_logging_level log_level); + +/** + * \brief Creates a new handle (opaque structure) for the given cable model. + * The handle must be freed with \a hpcables_handle_del when no longer needed. + * \param model the cable model. + * \return NULL if an error occurred, otherwise a valid handle. + **/ +HPEXPORT cable_handle * HPCALL hpcables_handle_new(cable_model model); +/** + * \brief Deletes a handle (opaque structure) created by \a hpcables_handle_new(). + * \param handle the handle to be deleted. + * \return 0 if the deletion succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_handle_del(cable_handle * handle); +/** + * \brief Shows basic information about a handle. + * \param handle the handle to be dumped. + * \return 0 if the handle was non-NULL, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_handle_display(cable_handle * handle); + +/** + * \brief Retrieves the cable model from the given cable handle. + * \param handle the cable handle + * \return the cable model corresponding to the given handle. + */ +HPEXPORT cable_model HPCALL hpcables_get_model(cable_handle * handle); + +/** + * \brief Gets the read timeout (in ms) for the given cable handle. + * \param handle the cable handle + * \return the current read timeout, 0 if error. + */ +HPEXPORT int HPCALL hpcables_options_get_read_timeout(cable_handle * handle); +/** + * \brief Sets the timeout (in ms) for the given cable handle. + * \param handle the cable handle + * \param timeout the new timeout. + * \return 0 if the operation succeeded, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcables_options_set_read_timeout(cable_handle * handle, int timeout); + +/** + * \brief Probes the given cable. + * \param handle the handle to be probed. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_probe(cable_handle * handle); +/** + * \brief Opens the given cable. + * \param handle the handle to be opened. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_open(cable_handle * handle); +/** + * \brief Closes the given cable. + * \param handle the handle to be closed. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_close(cable_handle * handle); +/** + * \brief Sends data through the given cable. + * \param handle the cable handle. + * \param data the data to be sent. + * \param len the size of the data to be sent. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_send(cable_handle * handle, uint8_t * data, uint32_t len); +/** + * \brief Receives data through the given cable. + * \param handle the cable handle. + * \param data storage area for the data to be received. + * \param len storage area for the length of the received data. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_recv(cable_handle * handle, uint8_t ** data, uint32_t * len); + +/** + * \brief Detects usable cables and builds an array of uint8_t booleans corresponding to the items of enum cable_model. + * \param result storage area for the cable models which were found. Use \a hpcables_probe_free to free the allocated memory. + * \return the number of usable cables. 0 means severe problem (e.g. memory allocation failure), as the null cable is always usable. + */ +HPEXPORT int HPCALL hpcables_probe_cables(uint8_t ** result); +/** + * \brief Frees the result of probing, created by \a hpcables_probe_cables. + * \param models the memory to be freed. + * \return 0 if the operation succeeded, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcables_probe_free(uint8_t * models); +/** + * \brief Shows basic information about a probing result. + * \param models the probing information to be dumped. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_probe_display(uint8_t * models); + + + +/** + * \brief Converts a calculator model to a printable string. + * \param model the calculator model. + * \return the string corresponding to the calculator model. + **/ +HPEXPORT const char * HPCALL hpcables_model_to_string(cable_model model); +/** + * \brief Converts a string to a supported calculator model, if possible. + * \param str the string. + * \return the calculator model corresponding to the string, CALC_NONE if failed. + **/ +HPEXPORT cable_model HPCALL hpcables_string_to_model(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libhpcalcs/include/hpcalcs.h b/libhpcalcs/include/hpcalcs.h new file mode 100644 index 0000000..90f4f22 --- /dev/null +++ b/libhpcalcs/include/hpcalcs.h @@ -0,0 +1,424 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpcalcs.h Calcs: base part. + */ + +#ifndef __HPLIBS_CALCS_H__ +#define __HPLIBS_CALCS_H__ + +#include +#include +#include + +#include "hplibs.h" +#include "hpfiles.h" +#include "hpcables.h" + +//! Opaque type for internal _calc_fncts. +typedef struct _calc_fncts calc_fncts; +//! Opaque type for internal _calc_handle. +typedef struct _calc_handle calc_handle; + +//! Indices of the function pointers in _calc_fncts. +typedef enum { + CALC_FNCT_CHECK_READY = 0, + CALC_FNCT_GET_INFOS = 1, + CALC_FNCT_SET_DATE_TIME = 2, + CALC_FNCT_RECV_SCREEN = 3, + CALC_FNCT_SEND_FILE = 4, + CALC_FNCT_RECV_FILE = 5, + CALC_FNCT_RECV_BACKUP = 6, + CALC_FNCT_SEND_KEY = 7, + CALC_FNCT_SEND_KEYS = 8, + CALC_FNCT_SEND_CHAT = 9, + CALC_FNCT_RECV_CHAT = 10, + CALC_FNCT_LAST ///< Keep this one last +} calc_fncts_idx; + +//! Used in the bit field of _calc_fncts, indicating whether a given calculator supports a given operation. +typedef enum { + CALC_OPS_NONE = 0, + CALC_OPS_CHECK_READY = (1 << CALC_FNCT_CHECK_READY), + CALC_OPS_GET_INFOS = (1 << CALC_FNCT_GET_INFOS), + CALC_OPS_SET_DATE_TIME = (1 << CALC_FNCT_SET_DATE_TIME), + CALC_OPS_RECV_SCREEN = (1 << CALC_FNCT_RECV_SCREEN), + CALC_OPS_SEND_FILE = (1 << CALC_FNCT_SEND_FILE), + CALC_OPS_RECV_FILE = (1 << CALC_FNCT_RECV_FILE), + CALC_OPS_RECV_BACKUP = (1 << CALC_FNCT_RECV_BACKUP), + CALC_OPS_SEND_KEY = (1 << CALC_FNCT_SEND_KEY), + CALC_OPS_SEND_KEYS = (1 << CALC_FNCT_SEND_KEYS), + CALC_OPS_SEND_CHAT = (1 << CALC_FNCT_SEND_CHAT), + CALC_OPS_RECV_CHAT = (1 << CALC_FNCT_RECV_CHAT) +} calc_features_operations; + +//! Screenshot formats supported by the calculators, list is known to be incomplete. +typedef enum { + // 5 is triggered periodically by the official connectivity kit. It returns something with a PNG header, but much smaller. + CALC_SCREENSHOT_FORMAT_FIRST = 8, + CALC_SCREENSHOT_FORMAT_PRIME_PNG_320x240x16 = 8, + CALC_SCREENSHOT_FORMAT_PRIME_PNG_320x240x4 = 9, + CALC_SCREENSHOT_FORMAT_PRIME_PNG_160x120x16 = 10, + CALC_SCREENSHOT_FORMAT_PRIME_PNG_160x120x4 = 11, + CALC_SCREENSHOT_FORMAT_LAST ///< Keep this one last +} calc_screenshot_format; + +//! Structure containing information returned by the calculator. This will change a lot when the returned data is better documented. +typedef struct { + uint32_t size; + uint8_t * data; +} calc_infos; + +//! Internal structure containing information about the calculator, and function pointers. +struct _calc_fncts { + calc_model model; + const char * name; + const char * description; + int features; + int (*check_ready) (calc_handle * handle, uint8_t ** out_data, uint32_t * out_size); + int (*get_infos) (calc_handle * handle, calc_infos * infos); + int (*set_date_time) (calc_handle * handle, time_t timestamp); + int (*recv_screen) (calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); + int (*send_file) (calc_handle * handle, files_var_entry * file); + int (*recv_file) (calc_handle * handle, files_var_entry * request, files_var_entry ** out_file); + int (*recv_backup) (calc_handle * handle, files_var_entry *** out_vars); + int (*send_key) (calc_handle * handle, uint32_t code); + int (*send_keys) (calc_handle * handle, const uint8_t * data, uint32_t size); + int (*send_chat) (calc_handle * handle, const uint16_t * data, uint32_t size); + int (*recv_chat) (calc_handle * handle, uint16_t ** out_data, uint32_t * out_size); +}; + +//! Internal structure containing state about the calculator, returned and passed around by the user. +struct _calc_handle { + calc_model model; + void * handle; + const calc_fncts * fncts; + cable_handle * cable; + int attached; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. + int open; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. + int busy; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. +}; + + +//! Structure passed to \a hpcalcs_init, contains e.g. callbacks for logging and memory allocation. +typedef struct { + unsigned int version; ///< Config version number. + void (*log_callback)(const char *format, va_list args); ///< Callback function for receiving logging output. + hplibs_malloc_funcs * alloc_funcs; ///< Function pointers used for dynamic memory allocation. If NULL, the library defaults to malloc(), calloc(), realloc(), free(). +} hpcalcs_config; + +//! Latest revision of the \a hpcalcs_config struct layout supported by this version of the library. +#define HPCALCS_CONFIG_VERSION (1) + + +//! Structure defining a raw packet for the Prime, used at the lowest layer of the protocol implementation. +typedef struct +{ + uint32_t size; + uint8_t data[PRIME_RAW_HID_DATA_SIZE + 1]; +} prime_raw_hid_pkt; + + +//! Structure defining a virtual packet for the Prime, used at the middle layer of the protocol implementation (fragmented to / reassembled from raw packets). +typedef struct +{ + uint32_t size; + uint8_t * data; + uint8_t cmd; +} prime_vtl_pkt; + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initializes library internals. Must be called before any other libhpcalcs function. + * \param config pointer to struct containing e.g. callbacks passed to the library. + * \return Whether the initialization succeeded. + * \note the contents of alloc_funcs are copied. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpcalcs_init(hpcalcs_config * config); +/** + * \brief Tears down library internals. No other libhpcalcs function can be called after this one. + * \return Whether the teardown succeeded. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpcalcs_exit(void); + +/** + * \brief Returns the library version string. + * \return The library version string, usually under the form "X.Y.Z". + **/ +HPEXPORT const char* HPCALL hpcalcs_version_get(void); + +/** + * \brief Returns the calcs supported by the current build of the library. + * \return An integer containing a binary OR of (1 << CALC_*) values, where CALC_* values are defined in enum \a calc_model. + **/ +HPEXPORT uint32_t HPCALL hpcalcs_supported_calcs(void); + +/** + * \brief Gets the error message if the error was produced by this library + * \param number the error number (from internal error.h) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * \note the string is allocated with malloc(), therefore it must be freed with free(). + * \return 0 if the error was produced by this library, otherwise the error number (for propagation). + **/ +HPEXPORT int HPCALL hpcalcs_error_get(int number, char **message); + +/** + * \brief Sets the callback function used by the library for logging + * \param log_callback function pointer + */ +HPEXPORT void HPCALL hpcalcs_log_set_callback(void (*log_callback)(const char *format, va_list args)); +/** + * \brief Sets the log level of the library, for controlling how much logging output is produced. + * \param log_level log level (from hplibs.h) + * \return the previous log level + */ +HPEXPORT hplibs_logging_level HPCALL hpcalcs_log_set_level(hplibs_logging_level log_level); + + +/** + * \brief Create a new handle (opaque structure) for the given calc model. + * The handle must be freed with \a hpcalcs_handle_del when no longer needed. + * \param model the calculator model. + * \return NULL if an error occurred, otherwise a valid handle. + **/ +HPEXPORT calc_handle * HPCALL hpcalcs_handle_new(calc_model model); +/** + * \brief Deletes a handle (opaque structure) created by \a hpcalcs_handle_new(). + * \param handle the handle to be deleted. + * \return 0 if the deletion succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcalcs_handle_del(calc_handle * handle); +/** + * \brief Shows basic information about a handle + * \param handle the handle to be dumped. + * \return 0 if the handle was non-NULL, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcalcs_handle_display(calc_handle * handle); + +/** + * \brief Retrieves the calc model from the given calc handle. + * \param handle the calc handle + * \return the calc model corresponding to the given handle. + */ +HPEXPORT calc_model HPCALL hpcalcs_get_model(calc_handle * handle); + +/** + * \brief Opens and attaches the given cable for use with the given calculator. + * \param handle the calculator handle. + * \param cable the cable handle. + * \return 0 upon success, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcalcs_cable_attach(calc_handle * handle, cable_handle * cable); +/** + * \brief Closes and detaches the cable attached to the given calculator handle. + * \param handle the calculator handle. + * \return 0 upon success, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcalcs_cable_detach(calc_handle * handle); +/** + * \brief Retrieves the cable handle attached to the given calculator handle, if any. + * \param handle the calculator handle. + * \return NULL if an error occurred, otherwise a cable handle. + **/ +HPEXPORT cable_handle * HPCALL hpcalcs_cable_get(calc_handle * handle); + +/** + * \brief Checks whether the calculator is ready + * \param handle the calculator handle. + * \param out_data storage area for information contained in the calculator's reply. + * \param out_size storage area for size of the information contained in the calculator's reply. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_check_ready(calc_handle * handle, uint8_t ** out_data, uint32_t * out_size); +/** + * \brief Retrieves some information, such as firmware version, from the calculator. + * \param handle the calculator handle. + * \param infos storage area for information contained in the reply. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_get_infos(calc_handle * handle, calc_infos * infos); +/** + * \brief Sets the calculator's date and time from a standard C89 / *nix timestamp. + * \param handle the calculator handle. + * \param timestamp the timestamp since the Epoch (1970). + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_set_date_time(calc_handle * handle, time_t timestamp); +/** + * \brief Retrieves a screenshot from the calculator + * \param handle the calculator handle. + * \param format the desired screenshot format. + * \param out_data storage area for screenshot contained in the calculator's reply. + * \param out_size storage area for size of the screenshot contained in the calculator's reply. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_recv_screen(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); +/** + * \brief Sends a file to the calculator. + * \param handle the calculator handle. + * \param file information about the file to be sent. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_send_file(calc_handle * handle, files_var_entry * file); +/** + * \brief Receives a file from the calculator. + * \param handle the calculator handle. + * \param request information about the file to be received. + * \param out_file storage area for the file to be received. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_recv_file(calc_handle * handle, files_var_entry * request, files_var_entry ** out_file); +/** + * \brief Receives a backup (made of multiple files) from the calculator. + * \param handle the calculator handle. + * \param out_vars storage area for the files to be received. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_recv_backup(calc_handle * handle, files_var_entry *** out_vars); +/** + * \brief Sends a single keypress to the calculator. + * \param handle the calculator handle. + * \param code the key code. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_send_key(calc_handle * handle, uint32_t code); +/** + * \brief Sends potentially multiple keypresses to the calculator. + * \param handle the calculator handle. + * \param data the buffer containings key codes. + * \param size the size of the data in the buffer. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_send_keys(calc_handle * handle, const uint8_t * data, uint32_t size); +/** + * \brief Sends chat data to the calculator. + * \param handle the calculator handle. + * \param data the data to be sent (UTF-16LE string, with U+0000 terminator, without UTF-16 LE BOM). + * \param size the size of the data to be sent. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_send_chat(calc_handle * handle, const uint16_t * data, uint32_t size); +/** + * \brief Receives chat data from the calculator. + * \param handle the calculator handle. + * \param out_data storage area for the chat data contained in the calculator's reply. + * \param out_size storage area for size of the chat data contained in the calculator's reply. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_recv_chat(calc_handle * handle, uint16_t ** out_data, uint32_t * out_size); + + +/** + * \brief Sends the given raw packet to the Prime calculator using given calculator handle. + * \param handle the calculator handle. + * \param pkt the raw packet. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_send(calc_handle * handle, prime_raw_hid_pkt * pkt); +/** + * \brief Receives a raw packet from the Prime calculator using given calculator handle, and store the result to given packet. + * \param handle the calculator handle. + * \param pkt the dest raw packet. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_recv(calc_handle * handle, prime_raw_hid_pkt * pkt); + +/** + * \brief Probes the given cable model to find out what calculator is connected to it. + * \param cable the cable model to be probed. + * \param out_calc storage area for the calculator model attached to the cable (if any). + * \return 0 upon success, nonzero otherwise. + * \note For now, the calculator type is fully determined by the calculator type. This might change in the future. + */ +HPEXPORT int HPCALL hpcalcs_probe_calc(cable_model cable, calc_model * out_calc); + + +/** + * \brief Creates a virtual packet for the Prime calculator, preallocating the given size. + * \param size the size to be preallocated. + * \return NULL if an error occurred, a virtual packet otherwise. + */ +HPEXPORT prime_vtl_pkt * HPCALL prime_vtl_pkt_new(uint32_t size); +/** + * \brief Creates a virtual packet for the Prime calculator, filling it with the given size and data. + * \param size the size of the data. + * \param data the pre-allocated data (assumed to be allocated with the same memory allocator as the one given to libhpcalcs, if not using the default one). + * \return NULL if an error occurred, a virtual packet otherwise. + * \warning This function takes ownership of \a data. + */ +HPEXPORT prime_vtl_pkt * HPCALL prime_vtl_pkt_new_with_data_ptr(uint32_t size, uint8_t * data); +/** + * \brief Deletes a virtual packet for the Prime calculator. + * \param pkt the packet to be deleted. + */ +HPEXPORT void HPCALL prime_vtl_pkt_del(prime_vtl_pkt * pkt); + +/** + * \brief Sends the given virtual packet to the Prime calculator using given calculator handle. + * \param handle the calculator handle. + * \param pkt the virtual packet. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_send_data(calc_handle * handle, prime_vtl_pkt * pkt); +/** + * \brief Receives a virtual packet from the Prime calculator using given calculator handle, and store the result to given packet. + * \param handle the calculator handle. + * \param pkt the dest virtual packet. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_recv_data(calc_handle * handle, prime_vtl_pkt * pkt); +/** + * \brief Returns the packet size corresponding to command \a cmd, possibly corrected by the contents of \a data. + * \param cmd the command. + * \param data the data. + * \param size storage area for size of the data. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_data_size(uint8_t cmd, uint8_t * data, uint32_t * out_size); + + +/** + * \brief Converts a calculator model to a printable string. + * \param model the calculator model. + * \return the string corresponding to the calculator model. + **/ +HPEXPORT const char * HPCALL hpcalcs_model_to_string(calc_model model); +/** + * \brief Converts a string to a supported calculator model, if possible. + * \param str the string. + * \return the calculator model corresponding to the string, CALC_NONE if failed. + **/ +HPEXPORT calc_model HPCALL hpcalcs_string_to_model(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libhpcalcs/include/hpfiles.h b/libhpcalcs/include/hpfiles.h new file mode 100644 index 0000000..ad7aa50 --- /dev/null +++ b/libhpcalcs/include/hpfiles.h @@ -0,0 +1,283 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpfiles.h Files: base part. + */ + +#ifndef __HPLIBS_FILES_H__ +#define __HPLIBS_FILES_H__ + +#include +#include +#include +#include + +// As of 2013/11, too many environments still don't support . +// Since the only thing from this header libhpfiles uses (for now) is char16_t: +// * on modern GCC and Clang (the main targets of this code base), use the builtin __CHAR16_TYPE__ preprocessor define; +// * otherwise, fall back to uint16_t. +#ifdef __CHAR16_TYPE__ +typedef __CHAR16_TYPE__ char16_t; +#else +typedef uint16_t char16_t; +#endif + +#include "hplibs.h" +#include "filetypes.h" + +//! Maximum length of a variable name for the calculators supported by libhpfiles. +// Not sure the target calculators even support such long filenames... +#define FILES_VARNAME_MAXLEN 128 + +//! Generic structure for storing the contents of a variable, or requesting that a variable be sent. +typedef struct +{ + char16_t name[FILES_VARNAME_MAXLEN+1]; + + uint8_t type; + uint8_t model; + uint8_t invalid; ///< Set to nonzero by e.g. hpcalcs_calc_recv_file() if a packet loss was detected. + uint32_t size; + uint8_t* data; +} files_var_entry; + + +//! Structure passed to \a hpfiles_init, contains e.g. callbacks for logging and memory allocation. +typedef struct { + unsigned int version; ///< Config version number. + void (*log_callback)(const char *format, va_list args); ///< Callback function for receiving logging output. + hplibs_malloc_funcs * alloc_funcs; ///< Function pointers used for dynamic memory allocation. If NULL, the library defaults to malloc(), calloc(), realloc(), free(). +} hpfiles_config; + +//! Latest revision of the \a hpfiles_config struct layout supported by this version of the library. +#define HPFILES_CONFIG_VERSION (1) + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initializes library internals. Must be called before any other libhpfiles function. + * \param config pointer to struct containing e.g. callbacks passed to the library. + * \return Whether the initialization succeeded. + * \note the contents of alloc_funcs are copied. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpfiles_init(hpfiles_config * config); +/** + * \brief Tears down library internals. No other libhpfiles function can be called after this one. + * \return Whether the teardown succeeded. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpfiles_exit(void); + +/** + * \brief Returns the library version string. + * \return The library version string, usually under the form "X.Y.Z". + **/ +HPEXPORT const char* HPCALL hpfiles_version_get(void); + +/** + * \brief Gets the error message if the error was produced by this library + * \param number the error number (from internal error.h) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * \note the string is allocated with malloc(), therefore it must be freed with free(). + * \return 0 if the error was produced by this library, otherwise the error number (for propagation). + **/ +HPEXPORT int HPCALL hpfiles_error_get(int number, char **message); + +/** + * \brief Sets the callback function used by the library for logging + * \param log_callback function pointer + */ +HPEXPORT void HPCALL hpfiles_log_set_callback(void (*log_callback)(const char *format, va_list args)); +/** + * \brief Sets the log level of the library, for controlling how much logging output is produced. + * \param log_level log level (from hplibs.h) + * \return the previous log level + */ +HPEXPORT hplibs_logging_level HPCALL hpfiles_log_set_level(hplibs_logging_level log_level); + + +/** + * \brief Creates an empty files_var_entry structure. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create(void); +/** + * \brief Creates and preallocates a files_var_entry structure. + * \param size the size to be allocated. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_size(uint32_t size); +/** + * \brief Creates and fills a files_var_entry structure with the given data. + * \param data the data to be duplicated. + * \param size the size of the data. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_data(uint8_t * data, uint32_t size); +/** + * \brief Creates and fills a files_var_entry structure with the given preallocated data. + * \param data the data to be attached to the files_var_entry (assumed to be allocated with the same memory allocator as the one given to libhpfiles, if not using the default one). + * \param size the size of the data. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_data_ptr(uint8_t * data, uint32_t size); +/** + * \brief Creates and fills a files_var_entry structure with the given data. + * \param data the data to be copied + * \param size the size of the data. + * \param name the file name on the calculator side. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_data_and_name(uint8_t * data, uint32_t size, const char16_t * name); +/** + * \brief Creates and fills a files_var_entry structure from the given file, if it exists. + * \param file the FILE pointer to be used for filling in a files_var_entry instance. + * \param filename the UTF-16LE name of the file on the calculator side, can be NULL if you want to set it later. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_from_file(FILE * file, const char16_t * filename); +/** + * \brief Destroys the given files_var_entry instance (embedded data + the entry itself). + * \param entry the entry + */ +HPEXPORT void HPCALL hpfiles_ve_delete(files_var_entry * entry); + +/** + * \brief Allocates data for the \a data field of files_var_entry. + * \param size the size to be allocated + * \return Pointer to allocated data, NULL if failed. + */ +HPEXPORT void * HPCALL hpfiles_ve_alloc_data(uint32_t size); +/** + * \brief Copies files_var_entry and its content (if any) from pre-existing src to pre-existing dst. + * \param dst destination entry. + * \param src source entry. + * \return dst, NULL if failed. + **/ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_copy(files_var_entry * dst, files_var_entry * src); +/** + * \brief Duplicates files_var_entry and its content (if any) by creating a new instance. + * \param src source entry + * \return The new entry, NULL if failed. + **/ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_dup(files_var_entry * src); + +/** + * \brief Shows basic information about a variable entry + * \param entry the entry to be dumped. + * \return 0 if the handle was non-NULL, nonzero otherwise. + **/ +HPEXPORT int hpfiles_ve_display(files_var_entry * entry); + +/** + * \brief Creates a NULL-terminated array for storing the given number of potentially non-NULL files_var_entry pointers. + * \param element_count the number of pointers + * \return The new array containing element_count + 1 NULL pointers, NULL if failed. + **/ +HPEXPORT files_var_entry ** HPCALL hpfiles_ve_create_array(uint32_t element_count); +/** + * \brief Reallocates a NULL-terminated array for storing a new number of potentially non-NULL files_var_entry pointers. + * \param entries the array of entries. + * \param element_count the new number of pointers + * \return The new array containing element_count + 1 pointers, NULL if failed. + * \note If the array was enlarged, the new storage space isn't cleared. + **/ +HPEXPORT files_var_entry ** HPCALL hpfiles_ve_resize_array(files_var_entry ** entries, uint32_t element_count); +/** + * \brief Destroys the whole array of files_var_entry structs (including the structures themselves and their embedded data). + * \param entries the array to be destroyed. + **/ +HPEXPORT void HPCALL hpfiles_ve_delete_array(files_var_entry ** entries); + + +/** + * \brief Converts a calculator model to a printable string. + * \param model the calculator model. + * \return the string corresponding to the calculator model. + **/ +HPEXPORT const char * HPCALL hpfiles_model_to_string(calc_model model); +/** + * \brief Converts a string to a supported calculator model, if possible. + * \param str the string. + * \return the calculator model corresponding to the string, CALC_NONE if failed. + **/ +HPEXPORT calc_model HPCALL hpfiles_string_to_model(const char *str); + +/** + * \brief Converts a file type ID to a printable file type string, according to the given calculator model. + * \param model the calculator model + * \param type the file type ID + * \return the file type string corresponding to the given type ID, if any. + */ +HPEXPORT const char * HPCALL hpfiles_vartype2str(calc_model model, uint8_t type); +/** + * \brief Converts a file type (under string form) to a file type ID, according to the given calculator model. + * \param model the calculator model + * \param type the file type string + * \return the file type ID corresponding to the given type string, if any. + */ +HPEXPORT uint8_t HPCALL hpfiles_str2vartype(calc_model model, const char * type); +/** + * \brief Converts a file type to an extension, according to the given calculator model. + * \param model the calculator model + * \param type the file type ID + * \return the file extension corresponding to the given type, if any. + * \note may have to use char16_t instead of char... + */ +HPEXPORT const char * HPCALL hpfiles_vartype2fext(calc_model model, uint8_t type); +/** + * \brief Converts a file extension to a file type ID, according to the given calculator model. + * \param model the calculator model + * \param type the file type as string. + * \return the file type ID corresponding to the given extension, if any. + */ +HPEXPORT uint8_t HPCALL hpfiles_fext2vartype(calc_model model, const char * type); +/** + * \brief Converts a file path to a file type ID, according to the given calculator model. + * \param model the calculator model + * \param filepath the file path as string. + * \return the file type ID corresponding to the given file, if any. + */ +HPEXPORT uint8_t HPCALL hpfiles_filename2vartype(calc_model model, const char * filepath); +/** + * \brief Interprets a file path to a file type ID + calculator-side file name, according to the given calculator model. + * \param model the calculator model + * \param filepath the file path as string. + * \param out_type storage space for the file type ID corresponding to the given file, if any. + * \param out_calcfilename a dynamically allocated string containing the calculator-side filename (usually stripped from the computer-side file extension). + * \return 0 if parsing succeeded, nonzero otherwise. + * \note may have to use char16_t instead of char... + * \note the string is allocated with malloc(), therefore it must be freed with free(). + */ +HPEXPORT int HPCALL hpfiles_parsefilename(calc_model model, const char * filepath, uint8_t * out_type, char ** out_calcfilename); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libhpcalcs/include/hplibs.h b/libhpcalcs/include/hplibs.h new file mode 100644 index 0000000..254d66c --- /dev/null +++ b/libhpcalcs/include/hplibs.h @@ -0,0 +1,93 @@ +/* + * libhpfiles, libhpcables, libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hplibs.h Files, Cables, Calcs: definitions common to libhpfiles, libhpcables, libhpcalcs. + */ + +#ifndef __HPLIBS_H__ +#define __HPLIBS_H__ + +#include + +#include "export.h" + +//! Enumeration of cable types. +typedef enum { + CABLE_NUL = 0, + CABLE_PRIME_HID, + CABLE_MAX +} cable_model; + +//! Enumeration of calculator types. +typedef enum { + CALC_NONE = 0, + CALC_PRIME, + CALC_MAX +} calc_model; + +//! Enumeration of logging levels. +typedef enum { + LOG_LEVEL_ALL = 0, + LOG_LEVEL_DEBUG, + LOG_LEVEL_INFO, + LOG_LEVEL_WARN, + LOG_LEVEL_ERROR +} hplibs_logging_level; + +//! Struct containing function pointers used by the libraries for dynamic memory allocation. +typedef struct { + void * (*malloc)(size_t size); ///< A malloc()-compatible function + void * (*calloc) (size_t nmemb, size_t size); ///< A calloc()-compatible function + void * (*realloc)(void *ptr, size_t size); ///< A realloc()-compatible function + void (*free) (void *ptr); ///< A free()-compatible function +} hplibs_malloc_funcs; + +//! USB Vendor ID of Hewlett-Packard. +#define USB_VID_HP (0x03F0) +//! USB Product ID of the Prime calculator in firmware revisions < 8151. +#define USB_PID_PRIME1 (0x0441) +//! USB Product ID of the Prime calculator in firmware revisions >= 8151. +#define USB_PID_PRIME2 (0x1541) + +//! Size of a raw HID packet for the Prime. +#define PRIME_RAW_HID_DATA_SIZE (64) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Gets the error message if the error was produced by a libhp* library + * \param number the error number (from above) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * + * \return the error number. + **/ +HPEXPORT int HPCALL hplibs_error_get(int number, char **message); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libhpcalcs/include/hpopers.h b/libhpcalcs/include/hpopers.h new file mode 100644 index 0000000..f82e717 --- /dev/null +++ b/libhpcalcs/include/hpopers.h @@ -0,0 +1,180 @@ +/* + * libhpopers: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpopers.h Higher-level operations: base part. + */ + +#ifndef __HPLIBS_OPERS_H__ +#define __HPLIBS_OPERS_H__ + +#include +#include +#include + +#include "hplibs.h" +#include "hpfiles.h" +#include "hpcables.h" +#include "hpcalcs.h" + + +//! Structure passed to \a hpopers_init, contains e.g. callbacks for logging and memory allocation. +typedef struct { + unsigned int version; ///< Config version number. + void (*log_callback)(const char *format, va_list args); ///< Callback function for receiving logging output. + hplibs_malloc_funcs * alloc_funcs; ///< Function pointers used for dynamic memory allocation. If NULL, the library defaults to malloc(), calloc(), realloc(), free(). +} hpopers_config; + +//! Latest revision of the \a hpopers_config struct layout supported by this version of the library. +#define HPOPERS_CONFIG_VERSION (1) + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initializes library internals. Must be called before any other libhpopers function. + * \param config pointer to struct containing e.g. callbacks passed to the library. + * \return Whether the initialization succeeded. + * \note the contents of alloc_funcs are copied. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpopers_init(hpopers_config * config); +/** + * \brief Tears down library internals. No other libhpopers function can be called after this one. + * \return Whether the teardown succeeded. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpopers_exit(void); + +/** + * \brief Returns the library version string. + * \return The library version string, usually under the form "X.Y.Z". + **/ +HPEXPORT const char* HPCALL hpopers_version_get(void); + +/** + * \brief Gets the error message if the error was produced by this library + * \param number the error number (from internal error.h) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * \note the string is allocated with malloc(), therefore it must be freed with free(). + * \return 0 if the error was produced by this library, otherwise the error number (for propagation). + **/ +HPEXPORT int HPCALL hpopers_error_get(int number, char **message); + +/** + * \brief Sets the callback function used by the library for logging + * \param log_callback function pointer + */ +HPEXPORT void HPCALL hpopers_log_set_callback(void (*log_callback)(const char *format, va_list args)); +/** + * \brief Sets the log level of the library, for controlling how much logging output is produced. + * \param log_level log level (from hplibs.h) + * \return the previous log level + */ +HPEXPORT hplibs_logging_level HPCALL hpopers_log_set_level(hplibs_logging_level log_level); + + +// Tentative APIs, may change in the near future. + +/** + * \brief Retrieves a screenshot from the calculator, without any form of conversion + * \param handle the calculator handle. + * \param format the desired screenshot format. + * \param out_file struct FILE pointer for storing the output. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_recv_screen . + */ +HPEXPORT int HPCALL hpopers_oper_recv_screen_verbatim_to_file(calc_handle * handle, calc_screenshot_format format, FILE * out_file); +/** + * \brief Retrieves a screenshot from the calculator, and convert it to R8G8B8 before recompressing it as PNG. + * \param handle the calculator handle. + * \param format the desired screenshot format. + * \param out_data storage area for converted R8G8B8 screenshot. + * \param out_size storage area for size of the R8G8B8 screenshot contained in the calculator's reply. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_recv_screen and \a hpopers_oper_convert_raw_screen_to_png_r8g8b8. + */ +HPEXPORT int HPCALL hpopers_oper_recv_screen_png_r8g8b8(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); +/** + * \brief Retrieves a screenshot from the calculator, and convert it to R8G8B8 before recompressing it as PNG and writing it to a file. + * \param handle the calculator handle. + * \param format the desired screenshot format. + * \param out_file struct FILE pointer for storing the output. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpopers_oper_recv_screen_png_r8g8b8 . + */ +HPEXPORT int HPCALL hpopers_oper_recv_screen_png_r8g8b8_to_file(calc_handle * handle, calc_screenshot_format format, FILE * out_file); +/** + * \brief Converts a raw screenshot (output by e.g. \a hpcalcs_calc_recv_screen) to a more usual PNG R8G8B8 format. + * \param in_data storage area for raw screenshot. + * \param in_size storage area for size of the raw screenshot. + * \param format the desired screenshot format. + * \param out_data storage area for R8G8B8 screenshot. + * \param out_size storage area for size of the R8G8B8 screenshot. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpopers_oper_convert_raw_screen_to_png_r8g8b8(uint8_t * in_data, uint32_t in_size, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); +/** + * \brief Sends a file to the calculator. + * \param handle the calculator handle. + * \param file struct FILE pointer containing the contents to be sent. + * \param filename struct FILE pointer containing the contents to be sent. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_send_file . + */ +HPEXPORT int HPCALL hpopers_calc_send_file(calc_handle * handle, FILE * file, const char16_t * filename); +/** + * \brief Receives a file from the calculator. + * \param handle the calculator handle. + * \param calculator_filename name (on the calculator side) of the file to be received. + * \param file struct FILE pointer used for writing data. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_recv_file . + */ +HPEXPORT int HPCALL hpopers_calc_recv_file(calc_handle * handle, const char16_t * calculator_filename, FILE * file); +/** + * \brief Receives a backup (made of multiple files) from the calculator to a folder. + * \param handle the calculator handle. + * \param out_path name of the folder used as root for the files hierarchy. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_recv_backup . + */ +HPEXPORT int HPCALL hpopers_calc_recv_backup(calc_handle * handle, const char * out_path); +/** + * \brief Sends a backup (made of multiple files) from a folder to the calculator. + * \param handle the calculator handle. + * \param in_path name of the folder used as root for the files hierarchy. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_send_file (called in a loop) . + */ +HPEXPORT int HPCALL hpopers_calc_send_backup(calc_handle * handle, const char * in_path); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libhpcalcs/include/internal.h b/libhpcalcs/include/internal.h new file mode 100644 index 0000000..c64fa2f --- /dev/null +++ b/libhpcalcs/include/internal.h @@ -0,0 +1,32 @@ +/* + * libhpfiles, libhpcables, libhpcalcs, libhpopers: hand-helds support libraries. + * Copyright (C) 2015 Lionel Debroux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file internal.h Files, Cables, Calcs, Opers: internal definitions for libhpfiles, libhpcables, libhpcalcs, libhpopers. + */ + +#ifndef __HPLIBS_INTERNAL_H__ +#define __HPLIBS_INTERNAL_H__ + +extern hplibs_malloc_funcs hpfiles_alloc_funcs; +extern hplibs_malloc_funcs hpcables_alloc_funcs; +extern hplibs_malloc_funcs hpcalcs_alloc_funcs; +extern hplibs_malloc_funcs hpopers_alloc_funcs; + +#endif diff --git a/libhpcalcs/include/logging.h b/libhpcalcs/include/logging.h new file mode 100644 index 0000000..f7ba2c5 --- /dev/null +++ b/libhpcalcs/include/logging.h @@ -0,0 +1,56 @@ +/* + * libhpfiles, libhpcables, libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file logging.h Logging primitives. + */ + +#ifndef __HPLIBS_LOGGING_H__ +#define __HPLIBS_LOGGING_H__ + +#include + +void hpfiles_debug (const char *format, ...); +void hpfiles_info (const char *format, ...); +void hpfiles_warning (const char *format, ...); +void hpfiles_error (const char *format, ...); + + +void hpcables_debug (const char *format, ...); +void hpcables_info (const char *format, ...); +void hpcables_warning (const char *format, ...); +void hpcables_error (const char *format, ...); + + +void hpcalcs_debug (const char *format, ...); +void hpcalcs_info (const char *format, ...); +void hpcalcs_warning (const char *format, ...); +void hpcalcs_error (const char *format, ...); + + +void hpopers_debug (const char *format, ...); +void hpopers_info (const char *format, ...); +void hpopers_warning (const char *format, ...); +void hpopers_error (const char *format, ...); + +#endif diff --git a/libhpcalcs/include/prime_cmd.h b/libhpcalcs/include/prime_cmd.h new file mode 100644 index 0000000..b8a1994 --- /dev/null +++ b/libhpcalcs/include/prime_cmd.h @@ -0,0 +1,73 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file prime_cmd.h Calcs: Prime commands + */ + +#ifndef __HPLIBS_CALCS_PRIME_CMD_H__ +#define __HPLIBS_CALCS_PRIME_CMD_H__ + +#define CMD_PRIME_CHECK_READY (0xFF) +#define CMD_PRIME_GET_INFOS (0xFA) +#define CMD_PRIME_RECV_SCREEN (0xFC) +#define CMD_PRIME_RECV_BACKUP (0xF9) +#define CMD_PRIME_REQ_FILE (0xF8) +#define CMD_PRIME_RECV_FILE (0xF7) +#define CMD_PRIME_SEND_CHAT (0xF2) +#define CMD_PRIME_RECV_CHAT (0xF2) +#define CMD_PRIME_SEND_KEY (0xEC) +#define CMD_PRIME_SET_DATE_TIME (0xE7) + +HPEXPORT int HPCALL calc_prime_s_check_ready(calc_handle * handle); +HPEXPORT int HPCALL calc_prime_r_check_ready(calc_handle * handle, uint8_t ** out_data, uint32_t * out_size); + +HPEXPORT int HPCALL calc_prime_s_get_infos(calc_handle * handle); +HPEXPORT int HPCALL calc_prime_r_get_infos(calc_handle * handle, calc_infos * infos); + +HPEXPORT int HPCALL calc_prime_s_set_date_time(calc_handle * handle, time_t timestamp); +HPEXPORT int HPCALL calc_prime_r_set_date_time(calc_handle * handle); + +HPEXPORT int HPCALL calc_prime_s_recv_screen(calc_handle * handle, calc_screenshot_format format); +HPEXPORT int HPCALL calc_prime_r_recv_screen(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); + +HPEXPORT int HPCALL calc_prime_s_send_file(calc_handle * handle, files_var_entry * file); +HPEXPORT int HPCALL calc_prime_r_send_file(calc_handle * handle); + +HPEXPORT int HPCALL calc_prime_s_recv_file(calc_handle * handle, files_var_entry * file); +HPEXPORT int HPCALL calc_prime_r_recv_file(calc_handle * handle, files_var_entry ** out_file); + +HPEXPORT int HPCALL calc_prime_s_recv_backup(calc_handle * handle); +HPEXPORT int HPCALL calc_prime_r_recv_backup(calc_handle * handle, files_var_entry *** out_vars); + +HPEXPORT int HPCALL calc_prime_s_send_key(calc_handle * handle, uint32_t code); +HPEXPORT int HPCALL calc_prime_r_send_key(calc_handle * handle); +HPEXPORT int HPCALL calc_prime_s_send_keys(calc_handle * handle, const uint8_t * data, uint32_t size); +HPEXPORT int HPCALL calc_prime_r_send_keys(calc_handle * handle); + +HPEXPORT int HPCALL calc_prime_s_send_chat(calc_handle * handle, const uint16_t * data, uint32_t size); +HPEXPORT int HPCALL calc_prime_r_send_chat(calc_handle * handle); + +HPEXPORT int HPCALL calc_prime_r_recv_chat(calc_handle * handle, uint16_t ** out_data, uint32_t * out_size); + +#endif diff --git a/libhpcalcs/include/typesprime.h b/libhpcalcs/include/typesprime.h new file mode 100644 index 0000000..5cf7d26 --- /dev/null +++ b/libhpcalcs/include/typesprime.h @@ -0,0 +1,69 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file typesprime.h Files: Prime file types and utility functions. + */ + +#ifndef __HPLIBS_FILES_TYPESPRIME_H__ +#define __HPLIBS_FILES_TYPESPRIME_H__ + +#define PRIME_TYPE_SETTINGS (0x00) +// 0x01 ? +#define PRIME_TYPE_APP (0x02) +#define PRIME_TYPE_LIST (0x03) // variables L0-L9, for instance +#define PRIME_TYPE_MATRIX (0x04) // variables M0-M9, for instance +#define PRIME_TYPE_NOTE (0x05) +#define PRIME_TYPE_PRGM (0x06) // programs with identical data are sent twice during backup ?? +#define PRIME_TYPE_APPNOTE (0x07) // XXX Tentative +#define PRIME_TYPE_APPPRGM (0x08) // XXX Tentative +#define PRIME_TYPE_COMPLEX (0x09) // variables Z0-Z9, for instance +#define PRIME_TYPE_REAL (0x0A) // variables A-Z, 0x3B8 (theta), for instance +#define PRIME_TYPE_TESTMODECONFIG (0x0B) +#define PRIME_TYPE_UNKNOWN (0xFF) + +//! Return the string corresponding to the file type ID +const char * prime_vartype2str(uint8_t type); + +//! Return the type ID corresponding to the string +uint8_t prime_str2vartype(const char * type); + +//! Return the file extension corresponding to the value +const char * prime_byte2fext(uint8_t type); + +//! Return the type value corresponding to the file extension +uint8_t prime_fext2byte(const char * type); + +//! Return the description corresponding to the value +const char * prime_byte2desc(uint8_t type); + +//! Return the type value corresponding to the file path +uint8_t prime_filename2byte(const char * filepath); + +//! Parse the file name + extension and determines the type value and calculator-side filename +int prime_parsesplitfilename(char * file, char * extension, uint8_t * out_type, char ** out_calcfilename); + +//! Parse the file path and determines the type value and calculator-side filename +int prime_parsefilename(const char * filepath, uint8_t * out_type, char ** out_calcfilename); + +#endif diff --git a/libhpcalcs/include/utils.h b/libhpcalcs/include/utils.h new file mode 100644 index 0000000..e8d17b1 Binary files /dev/null and b/libhpcalcs/include/utils.h differ diff --git a/libhpcalcs/src/calc_none.c b/libhpcalcs/src/calc_none.c new file mode 100644 index 0000000..a151213 --- /dev/null +++ b/libhpcalcs/src/calc_none.c @@ -0,0 +1,95 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file calc_prime.c Calcs: Prime top_level functions and structures. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +static int calc_none_check_ready(calc_handle * handle, uint8_t ** out_data, uint32_t * out_size) { + return 0; +} + +static int calc_none_get_infos(calc_handle * handle, calc_infos * infos) { + return 0; +} + +static int calc_none_set_date_time(calc_handle * handle, time_t timestamp) { + return 0; +} + +static int calc_none_recv_screen(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size) { + return 0; +} + +static int calc_none_send_file(calc_handle * handle, files_var_entry * file) { + return 0; +} + +static int calc_none_recv_file(calc_handle * handle, files_var_entry * request, files_var_entry ** out_file) { + return 0; +} + +static int calc_none_recv_backup(calc_handle * handle, files_var_entry *** out_vars) { + return 0; +} + +static int calc_none_send_key(calc_handle * handle, uint32_t code) { + return 0; +} + +static int calc_none_send_keys(calc_handle * handle, const uint8_t * data, uint32_t size) { + return 0; +} + +static int calc_none_send_chat(calc_handle * handle, const uint16_t * data, uint32_t size) { + return 0; +} + +static int calc_none_recv_chat(calc_handle * handle, uint16_t ** out_data, uint32_t * out_size) { + return 0; +} + +const calc_fncts calc_none_fncts = +{ + CALC_NONE, + "Dummy calculator", + "Dummy calculator used when no calculator is set", + 0, + &calc_none_check_ready, + &calc_none_get_infos, + &calc_none_set_date_time, + &calc_none_recv_screen, + &calc_none_send_file, + &calc_none_recv_file, + &calc_none_recv_backup, + &calc_none_send_key, + &calc_none_send_keys, + &calc_none_send_chat, + &calc_none_recv_chat +}; diff --git a/libhpcalcs/src/calc_prime.c b/libhpcalcs/src/calc_prime.c new file mode 100644 index 0000000..4525b1f --- /dev/null +++ b/libhpcalcs/src/calc_prime.c @@ -0,0 +1,226 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file calc_prime.c Calcs: Prime top_level functions and structures. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "logging.h" + +#include "prime_cmd.h" + +static int calc_prime_check_ready(calc_handle * handle, uint8_t ** out_data, uint32_t * out_size) { + int res; + + res = calc_prime_s_check_ready(handle); + if (res == 0) { + res = calc_prime_r_check_ready(handle, out_data, out_size); + if (res != 0) { + hpcalcs_error("%s: r_check_ready failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_check_ready failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_get_infos(calc_handle * handle, calc_infos * infos) { + int res; + + res = calc_prime_s_get_infos(handle); + if (res == 0) { + res = calc_prime_r_get_infos(handle, infos); + if (res != 0) { + hpcalcs_error("%s: r_get_infos failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_get_infos failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_set_date_time(calc_handle * handle, time_t timestamp) { + int res; + + res = calc_prime_s_set_date_time(handle, timestamp); + if (res == 0) { + res = calc_prime_r_set_date_time(handle); + if (res != 0) { + hpcalcs_error("%s: r_set_date_time failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_set_date_time failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_recv_screen(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size) { + int res; + + res = calc_prime_s_recv_screen(handle, format); + if (res == 0) { + res = calc_prime_r_recv_screen(handle, format, out_data, out_size); + if (res != 0) { + hpcalcs_error("%s: r_recv_screen failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_recv_screen failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_send_file(calc_handle * handle, files_var_entry * file) { + int res; + + res = calc_prime_s_send_file(handle, file); + if (res == 0) { + res = calc_prime_r_send_file(handle); + if (res != 0) { + hpcalcs_error("%s: r_send_file failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_send_file failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_recv_file(calc_handle * handle, files_var_entry * request, files_var_entry ** out_file) { + int res; + + res = calc_prime_s_recv_file(handle, request); + if (res == 0) { + res = calc_prime_r_recv_file(handle, out_file); + if (res != 0) { + hpcalcs_error("%s: r_recv_file failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_recv_file failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_recv_backup(calc_handle * handle, files_var_entry *** out_vars) { + int res; + + res = calc_prime_s_recv_backup(handle); + if (res == 0) { + res = calc_prime_r_recv_backup(handle, out_vars); + if (res != 0) { + hpcalcs_error("%s: r_recv_backup failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_recv_backup failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_send_key(calc_handle * handle, uint32_t code) { + int res; + + res = calc_prime_s_send_key(handle, code); + if (res == 0) { + res = calc_prime_r_send_key(handle); + if (res != 0) { + hpcalcs_error("%s: r_send_key failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_send_key failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_send_keys(calc_handle * handle, const uint8_t * data, uint32_t size) { + int res; + + res = calc_prime_s_send_keys(handle, data, size); + if (res == 0) { + res = calc_prime_r_send_keys(handle); + if (res != 0) { + hpcalcs_error("%s: r_send_keys failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_send_keys failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_send_chat(calc_handle * handle, const uint16_t * data, uint32_t size) { + int res; + + res = calc_prime_s_send_chat(handle, data, size); + if (res == 0) { + res = calc_prime_r_send_chat(handle); + if (res != 0) { + hpcalcs_error("%s: r_send_chat failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: s_send_chat failed", __FUNCTION__); + } + return res; +} + +static int calc_prime_recv_chat(calc_handle * handle, uint16_t ** out_data, uint32_t * out_size) { + int res; + + res = calc_prime_r_recv_chat(handle, out_data, out_size); + if (res != 0) { + hpcalcs_error("%s: r_recv_chat failed", __FUNCTION__); + } + return res; +} + +const calc_fncts calc_prime_fncts = +{ + CALC_PRIME, + "HP Prime", + "HP Prime Graphing Calculator", + CALC_OPS_CHECK_READY | CALC_OPS_GET_INFOS | CALC_OPS_SET_DATE_TIME | CALC_OPS_RECV_SCREEN + | CALC_OPS_SEND_FILE | CALC_OPS_RECV_FILE | CALC_OPS_RECV_BACKUP | CALC_OPS_SEND_KEY + | CALC_OPS_SEND_KEYS | CALC_OPS_SEND_CHAT | CALC_OPS_RECV_CHAT, + &calc_prime_check_ready, + &calc_prime_get_infos, + &calc_prime_set_date_time, + &calc_prime_recv_screen, + &calc_prime_send_file, + &calc_prime_recv_file, + &calc_prime_recv_backup, + &calc_prime_send_key, + &calc_prime_send_keys, + &calc_prime_send_chat, + &calc_prime_recv_chat +}; diff --git a/libhpcalcs/src/error.c b/libhpcalcs/src/error.c new file mode 100644 index 0000000..f370187 --- /dev/null +++ b/libhpcalcs/src/error.c @@ -0,0 +1,256 @@ +/* libhpcalcs - hand-helds support library + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file error.c Files / cables / calcs: Error functions. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifndef _WIN32 +// For strdup +#define _BSD_SOURCE +#endif +#include + +#include +#include +#include +#include +#include "logging.h" +#include "error.h" +#include "gettext.h" + +HPEXPORT int HPCALL hpfiles_error_get(int number, char **message) { + int ret = number; + //hpfiles_debug("%s: entering", __FUNCTION__); + if (message != NULL) { + if (number >= ERR_FILE_FIRST && number <= ERR_FILE_LAST) { + switch (number) { + case ERR_FILE_FILENAME: + *message = strdup(_("Cannot understand filename")); + break; + default: + *message = strdup(_("")); + break; + } + ret = 0; + } + else { + *message = NULL; + } + } + else { + hpfiles_error("%s: message is NULL", __FUNCTION__); + } + //hpfiles_debug("%s: exiting %d", __FUNCTION__, ret); + return ret; +} + +HPEXPORT int HPCALL hpcables_error_get(int number, char **message) { + int ret = number; + //hpcables_debug("%s: entering", __FUNCTION__); + if (message != NULL) { + if (number >= ERR_CABLE_FIRST && number <= ERR_CABLE_LAST) { + switch (number) { + case ERR_CABLE_NOT_OPEN: + *message = strdup(_("Cable is not open")); + break; + case ERR_CABLE_OPEN: + *message = strdup(_("Cable is already open")); + break; + case ERR_CABLE_BUSY: + *message = strdup(_("Cable is busy")); + break; + case ERR_CABLE_WRITE_ERROR: + *message = strdup(_("Error writing to cable")); + break; + case ERR_CABLE_READ_ERROR: + *message = strdup(_("Error reading from cable")); + break; + case ERR_CABLE_INVALID_FNCTS: + *message = strdup(_("Invalid cable functions")); + break; + case ERR_CABLE_PROBE_FAILED: + *message = strdup(_("Cable probing failed")); + break; + default: + *message = strdup(_("")); + break; + } + ret = 0; + } + else { + *message = NULL; + } + } + else { + hpcables_error("%s: message is NULL", __FUNCTION__); + } + //hpcables_debug("%s: exiting %d", __FUNCTION__, ret); + return ret; +} + +HPEXPORT int HPCALL hpcalcs_error_get(int number, char **message) { + int ret = number; + //hpcalcs_debug("%s: entering", __FUNCTION__); + if (message != NULL) { + if (number >= ERR_CALC_FIRST && number <= ERR_CALC_LAST) { + switch (number) { + case ERR_CALC_NO_CABLE: + *message = strdup(_("No cable attached")); + break; + case ERR_CALC_CABLE_NOT_OPEN: + *message = strdup(_("Cable is not open")); + break; + case ERR_CALC_BUSY: + *message = strdup(_("Calc is busy")); + break; + case ERR_CALC_INVALID_FNCTS: + *message = strdup(_("Invalid cable functions")); + break; + case ERR_CALC_PACKET_FORMAT: + *message = strdup(_("Unhandled packet format")); + break; + case ERR_CALC_SPLIT_TIMESTAMP: + *message = strdup(_("Unable to get time constituents")); + break; + case ERR_CALC_PROBE_FAILED: + *message = strdup(_("Calc probing failed")); + break; + default: + *message = strdup(_("")); + break; + } + ret = 0; + } + else { + *message = NULL; + } + } + else { + hpcalcs_error("%s: message is NULL", __FUNCTION__); + } + //hpcalcs_debug("%s: exiting %d", __FUNCTION__, ret); + return ret; +} + +HPEXPORT int HPCALL hpopers_error_get(int number, char **message) { + int ret = number; + //hpopers_debug("%s: entering", __FUNCTION__); + if (message != NULL) { + if (number >= ERR_OPER_FIRST && number <= ERR_OPER_LAST) { + switch (number) { + default: + *message = strdup(_("")); + break; + } + ret = 0; + } + else { + *message = NULL; + } + } + else { + hpopers_error("%s: message is NULL", __FUNCTION__); + } + //hpopers_debug("%s: exiting %d", __FUNCTION__, ret); + return ret; +} + +HPEXPORT int HPCALL hplibs_error_get(int number, char **message) { + int err = number; + char *s = NULL; + + if (message != NULL) { + // Skip ERR_SUCCESS. + if (number > ERR_HPLIBS_GENERIC_FIRST && number <= ERR_HPLIBS_GENERIC_LAST) { + switch (number) { + case ERR_MALLOC: + *message = strdup(_("Failed to allocate memory")); + break; + case ERR_INVALID_HANDLE: + *message = strdup(_("Invalid handle pointer")); + break; + case ERR_INVALID_PARAMETER: + *message = strdup(_("Invalid function parameter")); + break; + case ERR_INVALID_MODEL: + *message = strdup(_("Invalid model")); + break; + case ERR_LIBRARY_INIT: + *message = strdup(_("Problem initializing the library")); + break; + case ERR_LIBRARY_EXIT: + *message = strdup(_("Problem deinitializing the library")); + break; + default: + *message = strdup(_("")); + break; + } + return 0; + } + else { + // Retrieve the error message. + err = hpfiles_error_get(err, &s); + if (err) { + free(s); + err = hpcables_error_get(err, &s); + if (err) { + free(s); + err = hpcalcs_error_get(err, &s); + if (err) { + free(s); + err = hpopers_error_get(err, &s); + if (err) { + // next level: not a libhp* error. + free(s); + s = NULL; + } + else { + hpopers_info("%s\n", s); + } + } + else { + hpcalcs_info("%s\n", s); + } + } + else { + hpcables_info("%s\n", s); + } + } + else { + hpfiles_info("%s\n", s); + } + + *message = s; + } + } + else { + hpcalcs_error("%s: message is NULL", __FUNCTION__); + return number; + } + + return number; +} diff --git a/libhpcalcs/src/error.h b/libhpcalcs/src/error.h new file mode 100644 index 0000000..5d5ebd2 --- /dev/null +++ b/libhpcalcs/src/error.h @@ -0,0 +1,71 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file error.h Files / cables / calcs: Error IDs. + */ + +#ifndef __HPLIBS_CALCS_ERROR_H__ +#define __HPLIBS_CALCS_ERROR_H__ + +typedef enum { + ERR_HPLIBS_GENERIC_FIRST = 0, + ERR_SUCCESS = 0, // Must be equal to ERR_HPLIBS_GENERIC_FIRST + ERR_MALLOC, + ERR_INVALID_HANDLE, + ERR_INVALID_PARAMETER, + ERR_INVALID_MODEL, + ERR_LIBRARY_INIT, + ERR_LIBRARY_EXIT, + ERR_LIBRARY_CONFIG_VERSION, + ERR_HPLIBS_GENERIC_LAST = 127, + + ERR_FILE_FIRST = 128, + ERR_FILE_FILENAME = 128, + ERR_FILE_LAST = 255, + + ERR_CABLE_FIRST = 256, + ERR_CABLE_NOT_OPEN = 256, + ERR_CABLE_OPEN, + ERR_CABLE_BUSY, + ERR_CABLE_WRITE_ERROR, + ERR_CABLE_READ_ERROR, + ERR_CABLE_INVALID_FNCTS, + ERR_CABLE_PROBE_FAILED, + ERR_CABLE_LAST = 383, + + ERR_CALC_FIRST = 384, + ERR_CALC_NO_CABLE = 384, + ERR_CALC_CABLE_NOT_OPEN, + ERR_CALC_BUSY, + ERR_CALC_INVALID_FNCTS, + ERR_CALC_PACKET_FORMAT, + ERR_CALC_SPLIT_TIMESTAMP, + ERR_CALC_PROBE_FAILED, + ERR_CALC_LAST = 511, + + ERR_OPER_FIRST = 512, + ERR_OPER_LAST = 639 +} hplibs_error; + +#endif diff --git a/libhpcalcs/src/export.h b/libhpcalcs/src/export.h new file mode 100644 index 0000000..2505dbb --- /dev/null +++ b/libhpcalcs/src/export.h @@ -0,0 +1,91 @@ +/* + * libhpfiles, libhpcables, libhpcalcs - hand-helds support library + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file export.h Stuff for function export and calling convention. + */ + +#ifndef __HPCALCS_EXPORT__ +#define __HPCALCS_EXPORT__ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Calling convention: default +#define HPCALL + +// Symbols export +#if defined(HAVE_FVISIBILITY) // GCC 4.0 has introduced the -fvisibility flag (similar to declspec) +#define HPEXPORT __attribute__ ((visibility("default"))) + +#elif defined(__WIN32__) +# if defined(_MSC_VER) // MSVC 5.0 mini +# if defined(HPCALCS_EXPORTS) +# define HPEXPORT __declspec(dllexport) +# else +# define HPEXPORT __declspec(dllimport) +# endif + +# elif defined(__MINGW32__) // MinGW - GCC for Windows, (c) 2002 Kevin Kofler +# if defined(HPCALCS_EXPORTS) // defined by the configure script +# define HPEXPORT __declspec(dllexport) +# else +# define HPEXPORT __declspec(dllimport) +# endif +# endif + +#else +# define HPEXPORT // default +#endif + +#ifdef __cplusplus +} +#endif + +// Symbols deprecation +#ifndef HPLIBS_DEPRECATED +# ifdef __GNUC__ +# if (__GNUC__>3) || (__GNUC__==3 && __GNUC_MINOR__>=3) +# define HPLIBS_DEPRECATED __attribute__((deprecated)) +# else /* not GCC >= 3.3 */ +# define HPLIBS_DEPRECATED +# endif /* GCC >= 3.3 */ +# else /* not __GNUC__ */ +# ifdef _MSC_VER +# if _MSC_VER >= 1300 +# define HPLIBS_DEPRECATED __declspec(deprecated) +# else /* not _MSC_VER >= 1300 */ +# define HPLIBS_DEPRECATED +# endif /* _MSC_VER >= 1300 */ +# else /* not _MSC_VER */ +# define HPLIBS_DEPRECATED +# endif /* _MSC_VER */ +# endif /* __GNUC__ */ +#endif /* HPLIBS_DEPRECATED */ + +#endif diff --git a/libhpcalcs/src/filetypes.c b/libhpcalcs/src/filetypes.c new file mode 100644 index 0000000..13039fc --- /dev/null +++ b/libhpcalcs/src/filetypes.c @@ -0,0 +1,112 @@ +/* + * libhpfiles, libhpcables, libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file filetypes.c Files: File type utility functions. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "logging.h" +#include "error.h" + +#include "filetypes.h" + +HPEXPORT const char * HPCALL hpfiles_vartype2str(calc_model model, uint8_t type) { + switch (model) { + case CALC_PRIME: + return prime_vartype2str(type); + default: + hpfiles_error("%s: invalid model argument", __FUNCTION__); + return ""; + } +} + +HPEXPORT uint8_t HPCALL hpfiles_str2vartype(calc_model model, const char * type) { + if (type == NULL) { + hpfiles_error("%s: invalid type argument", __FUNCTION__); + return HPLIBS_FILE_TYPE_UNKNOWN; + } + switch (model) { + case CALC_PRIME: + return prime_str2vartype(type); + default: + hpfiles_error("%s: invalid model argument", __FUNCTION__); + return HPLIBS_FILE_TYPE_UNKNOWN; + } +} + +HPEXPORT const char * HPCALL hpfiles_vartype2fext(calc_model model, uint8_t type) { + switch (model) { + case CALC_PRIME: + return prime_byte2fext(type); + default: + hpfiles_error("%s: invalid model argument", __FUNCTION__); + return ""; + } +} + +HPEXPORT uint8_t HPCALL hpfiles_fext2vartype(calc_model model, const char * type) { + if (type == NULL) { + hpfiles_error("%s: invalid type argument", __FUNCTION__); + return HPLIBS_FILE_TYPE_UNKNOWN; + } + switch (model) { + case CALC_PRIME: + return prime_fext2byte(type); + default: + hpfiles_error("%s: invalid model argument", __FUNCTION__); + return HPLIBS_FILE_TYPE_UNKNOWN; + } +} + +HPEXPORT uint8_t HPCALL hpfiles_filename2vartype(calc_model model, const char * filepath) { + if (filepath == NULL) { + hpfiles_error("%s: invalid filepath argument", __FUNCTION__); + return HPLIBS_FILE_TYPE_UNKNOWN; + } + switch (model) { + case CALC_PRIME: + return prime_filename2byte(filepath); + default: + hpfiles_error("%s: invalid model argument", __FUNCTION__); + return HPLIBS_FILE_TYPE_UNKNOWN; + } +} + +HPEXPORT int HPCALL hpfiles_parsefilename(calc_model model, const char * filepath, uint8_t * out_type, char ** out_calcfilename) { + if (filepath == NULL || out_type == NULL || out_calcfilename == NULL) { + hpfiles_error("%s: an argument is NULL", __FUNCTION__); + return ERR_INVALID_PARAMETER; + } + switch (model) { + case CALC_PRIME: + return prime_parsefilename(filepath, out_type, out_calcfilename); + default: + hpfiles_error("%s: invalid model argument", __FUNCTION__); + return HPLIBS_FILE_TYPE_UNKNOWN; + } +} diff --git a/libhpcalcs/src/filetypes.h b/libhpcalcs/src/filetypes.h new file mode 100644 index 0000000..ddfd14c --- /dev/null +++ b/libhpcalcs/src/filetypes.h @@ -0,0 +1,35 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file filetypes.h Files: Umbrella header for file types. + */ + +#ifndef __HPLIBS_FILES_FILETYPES_H__ +#define __HPLIBS_FILES_FILETYPES_H__ + +#include "typesprime.h" + +#define HPLIBS_FILE_TYPE_UNKNOWN (0xFF) + +#endif diff --git a/libhpcalcs/src/gettext.h b/libhpcalcs/src/gettext.h new file mode 100644 index 0000000..1564ac7 --- /dev/null +++ b/libhpcalcs/src/gettext.h @@ -0,0 +1,60 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file gettext.h Files / cables / calcs: internationalization (i18n) stuff. + */ + +#ifndef HPLIBS_GETTEXT_H +#define HPLIBS_GETTEXT_H + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +#warning NLS disabled +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + +#endif diff --git a/libhpcalcs/src/hpcables.c b/libhpcalcs/src/hpcables.c new file mode 100644 index 0000000..33a8df3 --- /dev/null +++ b/libhpcalcs/src/hpcables.c @@ -0,0 +1,537 @@ +/* + * libhpcables: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpcables.c Cables: base part. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + +#include +#include "internal.h" +#include "logging.h" +#include "error.h" +#include "gettext.h" + + +extern const cable_fncts cable_nul_fncts; +extern const cable_fncts cable_prime_hid_fncts; + +const cable_fncts * hpcables_all_cables[CABLE_MAX] = { + &cable_nul_fncts, + &cable_prime_hid_fncts +}; + +static const uint32_t supported_cables = + (1U << CABLE_NUL) + | (1U << CABLE_PRIME_HID) +; + +hplibs_malloc_funcs hpcables_alloc_funcs = { + .malloc = malloc, + .calloc = calloc, + .realloc = realloc, + .free = free +}; + + +// not static, must be shared between instances +int hpcables_instance_count = 0; + +HPEXPORT int HPCALL hpcables_init(hpcables_config * config) { + int res = ERR_SUCCESS; + void (*log_callback)(const char *format, va_list args); + hplibs_malloc_funcs * alloc_funcs; + + if (config == NULL) { + log_callback = NULL; + alloc_funcs = NULL; + } + else { + if (config->version <= HPCABLES_CONFIG_VERSION) { + if (config->version == 1) { + log_callback = config->log_callback; + alloc_funcs = config->alloc_funcs; + } + else { + hpcables_error(_("%s: unsupported config version %u"), __FUNCTION__, config->version); + res = ERR_LIBRARY_CONFIG_VERSION; + } + } + else { + hpcables_error(_("%s: unsupported config version %u"), __FUNCTION__, config->version); + res = ERR_LIBRARY_CONFIG_VERSION; + } + } + + if (!res) { + // TODO: when (if) libhpcables is split from libhpcalcs, copy and adjust locale setting code from hpfiles.c. + + if (!hpcables_instance_count) { + hpcables_log_set_callback(log_callback); + if (alloc_funcs != NULL) { + hpcables_alloc_funcs = *alloc_funcs; + } + hpcables_info(_("hpcables library version %s"), hpcables_version_get()); + + res = hid_init(); + if (res == 0) { + res = ERR_SUCCESS; + hpcables_info(_("%s: init succeeded"), __FUNCTION__); + hpcables_instance_count++; + } + else { + res = ERR_LIBRARY_INIT; + hpcables_error(_("%s: init failed"), __FUNCTION__); + } + } + else { + res = ERR_SUCCESS; + hpcables_info(_("%s: re-init skipped"), __FUNCTION__); + hpcables_instance_count++; + } + } + + return res; +} + +HPEXPORT int HPCALL hpcables_exit(void) { + int res; + + if (hpcables_instance_count <= 0) { + hpcables_error(_("%s: more exits than inits"), __FUNCTION__); + res = ERR_LIBRARY_EXIT; + } + else { + if (hpcables_instance_count == 1) { + hid_exit(); + } + + hpcables_instance_count--; + + hpcables_info(_("%s: exit succeeded"), __FUNCTION__); + res = ERR_SUCCESS; + } + + return res; +} + + +HPEXPORT const char* HPCALL hpcables_version_get (void) { + return VERSION; +} + + +HPEXPORT uint32_t HPCALL hpcables_supported_cables (void) { + return supported_cables; +} + + +HPEXPORT cable_handle * HPCALL hpcables_handle_new(cable_model model) { + cable_handle * handle = NULL; + if (model < CABLE_MAX) { + handle = (cable_handle *)(hpcables_alloc_funcs.calloc)(1, sizeof(*handle)); + + if (handle != NULL) { + handle->model = model; + handle->handle = NULL; + handle->fncts = hpcables_all_cables[model]; + hpcables_info("%s: handle allocation for model %d succeeded", __FUNCTION__, model); + } + else { + hpcables_error("%s: handle allocation for model %d failed", __FUNCTION__, model ); + } + } + else { + hpcables_error("%s: invalid model %d", __FUNCTION__, model); + } + + return handle; +} + +HPEXPORT int HPCALL hpcables_handle_del(cable_handle * handle) { + int res; + if (handle != NULL) { + (hpcables_alloc_funcs.free)(handle->handle); + handle->handle = NULL; + + (hpcables_alloc_funcs.free)(handle); + res = ERR_SUCCESS; + hpcables_info("%s: handle deletion succeeded", __FUNCTION__); + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + + return res; +} + +HPEXPORT int HPCALL hpcables_handle_display(cable_handle * handle) { + int res; + if (handle != NULL) { + hpcables_info("Link cable handle details:"); + hpcables_info("\tmodel: %s", hpcables_model_to_string(handle->model)); + hpcables_info("\tread_timeout: %d", handle->read_timeout); + hpcables_info("\topen: %d", handle->open); + hpcables_info("\tbusy: %d", handle->busy); + res = ERR_SUCCESS; + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + + return res; +} + +HPEXPORT cable_model HPCALL hpcables_get_model(cable_handle * handle) { + cable_model model = CABLE_NUL; + if (handle != NULL) { + model = handle->model; + } + else { + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + + return model; +} + +#define DO_BASIC_HANDLE_CHECKS() \ + if (!handle->open) { \ + res = ERR_CABLE_NOT_OPEN; \ + hpcalcs_error("%s: cable not open", __FUNCTION__); \ + break; \ + } \ + DO_BASIC_HANDLE_CHECKS2() + +#define DO_BASIC_HANDLE_CHECKS2() \ + if (handle->busy) { \ + res = ERR_CABLE_BUSY; \ + hpcalcs_error("%s: cable busy", __FUNCTION__); \ + break; \ + } \ + if (handle->fncts == NULL) { \ + res = ERR_CABLE_INVALID_FNCTS; \ + hpcalcs_error("%s: fncts is NULL", __FUNCTION__); \ + break; \ + } + +HPEXPORT int HPCALL hpcables_options_get_read_timeout(cable_handle * handle) { + int timeout = 0; + if (handle != NULL) { + timeout = handle->read_timeout; + } + else { + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return timeout; +} + +HPEXPORT int HPCALL hpcables_options_set_read_timeout(cable_handle * handle, int read_timeout) { + int res; + if (handle != NULL) { + do { + int (*set_read_timeout) (cable_handle *, int); + + DO_BASIC_HANDLE_CHECKS2() + + set_read_timeout = handle->fncts->set_read_timeout; + if (set_read_timeout != NULL) { + handle->busy = 1; + res = (*set_read_timeout)(handle, read_timeout); + if (res == ERR_SUCCESS) { + hpcables_info("%s: set_read_timeout succeeded", __FUNCTION__); + } + else { + hpcables_error("%s: set_read_timeout failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CABLE_INVALID_FNCTS; + hpcables_error("%s: fncts->set_read_timeout is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcables_cable_probe(cable_handle * handle) { + int res; + if (handle != NULL) { + do { + int (*probe) (cable_handle *); + + DO_BASIC_HANDLE_CHECKS2() + + probe = handle->fncts->probe; + if (probe != NULL) { + handle->busy = 1; + res = (*probe)(handle); + if (res == ERR_SUCCESS) { + handle->open = 0; + hpcables_info("%s: probe succeeded", __FUNCTION__); + } + else { + hpcables_error("%s: probe failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CABLE_INVALID_FNCTS; + hpcables_error("%s: fncts->probe is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcables_cable_open(cable_handle * handle) { + int res; + if (handle != NULL) { + do { + int (*open) (cable_handle *); + + if (handle->open) { + res = ERR_CABLE_OPEN; + hpcables_error("%s: cable already open", __FUNCTION__); + break; + } + DO_BASIC_HANDLE_CHECKS2() + + open = handle->fncts->open; + if (open != NULL) { + handle->busy = 1; + res = (*open)(handle); + if (res == ERR_SUCCESS) { + handle->open = 1; + hpcables_info("%s: open succeeded", __FUNCTION__); + } + else { + hpcables_error("%s: open failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CABLE_INVALID_FNCTS; + hpcables_error("%s: fncts->open is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcables_cable_close(cable_handle * handle) { + int res; + if (handle != NULL) { + do { + int (*close) (cable_handle *); + + DO_BASIC_HANDLE_CHECKS() + + close = handle->fncts->close; + if (close != NULL) { + handle->busy = 1; + res = (*close)(handle); + if (res == ERR_SUCCESS) { + handle->open = 0; + hpcables_info("%s: close succeeded", __FUNCTION__); + } + else { + hpcables_error("%s: close failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CABLE_INVALID_FNCTS; + hpcables_error("%s: fncts->close is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcables_cable_send(cable_handle * handle, uint8_t * data, uint32_t len) { + int res; + if (handle != NULL) { + do { + int (*send) (cable_handle *, uint8_t *, uint32_t); + + DO_BASIC_HANDLE_CHECKS() + + send = handle->fncts->send; + if (send != NULL) { + handle->busy = 1; + res = (*send)(handle, data, len); + if (res == ERR_SUCCESS) { + //hpcables_info("%s: send succeeded", __FUNCTION__); + } + else { + hpcables_warning("%s: send failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CABLE_INVALID_FNCTS; + hpcables_error("%s: fncts->send is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcables_cable_recv(cable_handle * handle, uint8_t ** data, uint32_t * len) { + int res; + if (handle != NULL) { + do { + int (*recv) (cable_handle *, uint8_t **, uint32_t *); + + DO_BASIC_HANDLE_CHECKS() + + recv = handle->fncts->recv; + if (recv != NULL) { + handle->busy = 1; + res = (*recv)(handle, data, len); + if (res == ERR_SUCCESS) { + //hpcables_info("%s: recv succeeded", __FUNCTION__); + } + else { + hpcables_warning("%s: recv failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CABLE_INVALID_FNCTS; + hpcables_error("%s: fncts->recv is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +#undef DO_BASIC_HANDLE_CHECKS2 +#undef DO_BASIC_HANDLE_CHECKS + +HPEXPORT int HPCALL hpcables_probe_cables(uint8_t ** result) { + int res = 0; + if (result != NULL) { + uint8_t * models = (uint8_t *)(hpcables_alloc_funcs.calloc)(CABLE_MAX, sizeof(uint8_t)); + uint8_t * ptr = models; + if (models != NULL) { + for (cable_model model = CABLE_NUL; model < CABLE_MAX; model++) { + cable_handle * handle = hpcables_handle_new(model); + if (handle != NULL) { + if (hpcables_cable_probe(handle) == ERR_SUCCESS) { + res++; + *ptr++ = 1; + hpcables_info("%s: probing cable %s succeeded", __FUNCTION__, hpcables_model_to_string(model)); + } + else { + ptr++; + hpcables_error("%s: probing cable %s failed", __FUNCTION__, hpcables_model_to_string(model)); + } + + if (hpcables_handle_del(handle) != ERR_SUCCESS) { + hpcables_error("%s: failed to destroy handle for model %s", __FUNCTION__, hpcables_model_to_string(model)); + } + else { + hpcables_info("%s: destroy handle for model %s success", __FUNCTION__, hpcables_model_to_string(model)); + } + } + else { + hpcables_error("%s: failed to create handle for model %s", __FUNCTION__, hpcables_model_to_string(model)); + } + } + } + *result = models; + } + else { + hpcables_error("%s: result is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcables_probe_free(uint8_t * models) { + int res; + if (models != NULL) { + res = ERR_SUCCESS; + (hpcables_alloc_funcs.free)(models); + } + else { + res = ERR_INVALID_PARAMETER; + hpcables_error("%s: models is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcables_probe_display(uint8_t * models) { + int res; + if (models != NULL) { + cable_model model; + res = 0; + hpcables_info("Probing data details:"); + for (model = CABLE_NUL; model < CABLE_MAX; model++) { + if (models[model] != 0) { + hpcables_info("\tfound cable #%d: %s", model, hpcables_model_to_string(model)); + } + } + res = ERR_SUCCESS; + hpcables_info("%s found %d cables", __FUNCTION__, res); + } + else { + res = ERR_INVALID_PARAMETER; + hpcables_error("%s: models is NULL", __FUNCTION__); + } + return res; +} diff --git a/libhpcalcs/src/hpcables.h b/libhpcalcs/src/hpcables.h new file mode 100644 index 0000000..922477c --- /dev/null +++ b/libhpcalcs/src/hpcables.h @@ -0,0 +1,249 @@ +/* + * libhpcables: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpcables.h Cables: base part. + */ + +#ifndef __HPLIBS_CABLES_H__ +#define __HPLIBS_CABLES_H__ + +#include +#include + +#include "hplibs.h" + +//! Opaque type for internal _cable_fncts. +typedef struct _cable_fncts cable_fncts; +//! Opaque type for internal _cable_handle. +typedef struct _cable_handle cable_handle; + +//! Internal structure containing information about the cable, and function pointers. +struct _cable_fncts { + cable_model model; + const char * name; + const char * description; + int (*probe) (cable_handle * handle); + int (*open) (cable_handle * handle); + int (*close) (cable_handle * handle); + int (*set_read_timeout) (cable_handle * handle, int read_timeout); + int (*send) (cable_handle * handle, uint8_t * data, uint32_t len); + int (*recv) (cable_handle * handle, uint8_t ** data, uint32_t * len); +}; + +//! Internal structure containing state about the cable, returned and passed around by the user. +struct _cable_handle { + cable_model model; + void * handle; + const cable_fncts * fncts; + int read_timeout; + int open; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. + int busy; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. +}; + + +//! Structure passed to \a hpcables_init, contains e.g. callbacks for logging and memory allocation. +typedef struct { + unsigned int version; ///< Config version number. + void (*log_callback)(const char *format, va_list args); ///< Callback function for receiving logging output. + hplibs_malloc_funcs * alloc_funcs; ///< Function pointers used for dynamic memory allocation. If NULL, the library defaults to malloc(), calloc(), realloc(), free(). +} hpcables_config; + +//! Latest revision of the \a hpcables_config struct layout supported by this version of the library. +#define HPCABLES_CONFIG_VERSION (1) + + +typedef enum { + PACKET_DIRECTION_NONE = 0, + PACKET_DIRECTION_SEND, + PACKET_DIRECTION_RECV +} CablePacketDirection; + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initializes library internals. Must be called before any other libhpcables function. + * \param config pointer to struct containing e.g. callbacks passed to the library. + * \return Whether the initialization succeeded. + * \note the contents of alloc_funcs are copied. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpcables_init(hpcables_config * config); +/** + * \brief Tears down library internals. No other libhpcables function can be called after this one. + * \return Whether the teardown succeeded. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpcables_exit(void); + +/** + * \brief Returns the library version string. + * \return The library version string, usually under the form "X.Y.Z". + **/ +HPEXPORT const char* HPCALL hpcables_version_get(void); + +/** + * \brief Returns the cables supported by the current build of the library. + * \return An integer containing a binary OR of (1 << CABLE_*) values, where CABLE_* values are defined in enum \a cable_model. + **/ +HPEXPORT uint32_t HPCALL hpcables_supported_cables(void); + +/** + * \brief Gets the error message if the error was produced by this library + * \param number the error number (from internal error.h) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * \note the string is allocated with malloc(), therefore it must be freed with free(). + * \return 0 if the error was produced by this library, otherwise the error number (for propagation). + **/ +HPEXPORT int HPCALL hpcables_error_get(int number, char **message); + +/** + * \brief Sets the callback function used by the library for logging + * \param log_callback function pointer + */ +HPEXPORT void HPCALL hpcables_log_set_callback(void (*log_callback)(const char *format, va_list args)); +/** + * \brief Sets the log level of the library, for controlling how much logging output is produced. + * \param log_level log level (from hplibs.h) + * \return the previous log level + */ +HPEXPORT hplibs_logging_level HPCALL hpcables_log_set_level(hplibs_logging_level log_level); + +/** + * \brief Creates a new handle (opaque structure) for the given cable model. + * The handle must be freed with \a hpcables_handle_del when no longer needed. + * \param model the cable model. + * \return NULL if an error occurred, otherwise a valid handle. + **/ +HPEXPORT cable_handle * HPCALL hpcables_handle_new(cable_model model); +/** + * \brief Deletes a handle (opaque structure) created by \a hpcables_handle_new(). + * \param handle the handle to be deleted. + * \return 0 if the deletion succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_handle_del(cable_handle * handle); +/** + * \brief Shows basic information about a handle. + * \param handle the handle to be dumped. + * \return 0 if the handle was non-NULL, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_handle_display(cable_handle * handle); + +/** + * \brief Retrieves the cable model from the given cable handle. + * \param handle the cable handle + * \return the cable model corresponding to the given handle. + */ +HPEXPORT cable_model HPCALL hpcables_get_model(cable_handle * handle); + +/** + * \brief Gets the read timeout (in ms) for the given cable handle. + * \param handle the cable handle + * \return the current read timeout, 0 if error. + */ +HPEXPORT int HPCALL hpcables_options_get_read_timeout(cable_handle * handle); +/** + * \brief Sets the timeout (in ms) for the given cable handle. + * \param handle the cable handle + * \param timeout the new timeout. + * \return 0 if the operation succeeded, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcables_options_set_read_timeout(cable_handle * handle, int timeout); + +/** + * \brief Probes the given cable. + * \param handle the handle to be probed. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_probe(cable_handle * handle); +/** + * \brief Opens the given cable. + * \param handle the handle to be opened. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_open(cable_handle * handle); +/** + * \brief Closes the given cable. + * \param handle the handle to be closed. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_close(cable_handle * handle); +/** + * \brief Sends data through the given cable. + * \param handle the cable handle. + * \param data the data to be sent. + * \param len the size of the data to be sent. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_send(cable_handle * handle, uint8_t * data, uint32_t len); +/** + * \brief Receives data through the given cable. + * \param handle the cable handle. + * \param data storage area for the data to be received. + * \param len storage area for the length of the received data. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_cable_recv(cable_handle * handle, uint8_t ** data, uint32_t * len); + +/** + * \brief Detects usable cables and builds an array of uint8_t booleans corresponding to the items of enum cable_model. + * \param result storage area for the cable models which were found. Use \a hpcables_probe_free to free the allocated memory. + * \return the number of usable cables. 0 means severe problem (e.g. memory allocation failure), as the null cable is always usable. + */ +HPEXPORT int HPCALL hpcables_probe_cables(uint8_t ** result); +/** + * \brief Frees the result of probing, created by \a hpcables_probe_cables. + * \param models the memory to be freed. + * \return 0 if the operation succeeded, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcables_probe_free(uint8_t * models); +/** + * \brief Shows basic information about a probing result. + * \param models the probing information to be dumped. + * \return 0 if the operation succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcables_probe_display(uint8_t * models); + + + +/** + * \brief Converts a calculator model to a printable string. + * \param model the calculator model. + * \return the string corresponding to the calculator model. + **/ +HPEXPORT const char * HPCALL hpcables_model_to_string(cable_model model); +/** + * \brief Converts a string to a supported calculator model, if possible. + * \param str the string. + * \return the calculator model corresponding to the string, CALC_NONE if failed. + **/ +HPEXPORT cable_model HPCALL hpcables_string_to_model(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libhpcalcs/src/hpcalcs.c b/libhpcalcs/src/hpcalcs.c new file mode 100644 index 0000000..4c92870 --- /dev/null +++ b/libhpcalcs/src/hpcalcs.c @@ -0,0 +1,674 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpcalcs.c Calcs: base part. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include +#include "internal.h" +#include "logging.h" +#include "error.h" +#include "gettext.h" + +extern const calc_fncts calc_none_fncts; +extern const calc_fncts calc_prime_fncts; + +const calc_fncts * hpcalcs_all_calcs[CALC_MAX] = { + &calc_none_fncts, + &calc_prime_fncts +}; + +static const uint32_t supported_calcs = + (1U << CALC_NONE) + | (1U << CALC_PRIME) +; + +hplibs_malloc_funcs hpcalcs_alloc_funcs = { + .malloc = malloc, + .calloc = calloc, + .realloc = realloc, + .free = free +}; + + +// not static, must be shared between instances +int hpcalcs_instance_count = 0; + +HPEXPORT int HPCALL hpcalcs_init(hpcalcs_config * config) { + int res = ERR_SUCCESS; + void (*log_callback)(const char *format, va_list args); + hplibs_malloc_funcs * alloc_funcs; + + if (config == NULL) { + log_callback = NULL; + alloc_funcs = NULL; + } + else { + if (config->version <= HPCALCS_CONFIG_VERSION) { + if (config->version == 1) { + log_callback = config->log_callback; + alloc_funcs = config->alloc_funcs; + } + else { + hpcables_error(_("%s: unsupported config version %u"), __FUNCTION__, config->version); + res = ERR_LIBRARY_CONFIG_VERSION; + } + } + else { + hpcables_error(_("%s: unsupported config version %u"), __FUNCTION__, config->version); + res = ERR_LIBRARY_CONFIG_VERSION; + } + } + + if (!res) { + // TODO: when (if) libhpfiles is split from libhpcalcs, copy and adjust locale setting code from hpfiles.c. + + if (!hpcalcs_instance_count) { + hpcalcs_log_set_callback(log_callback); + if (alloc_funcs != NULL) { + hpcalcs_alloc_funcs = *alloc_funcs; + } + hpcalcs_info(_("hpcalcs library version %s"), hpcalcs_version_get()); + + hpcalcs_info(_("%s: init succeeded"), __FUNCTION__); + hpcalcs_instance_count++; + } + else { + hpcalcs_info(_("%s: re-init skipped"), __FUNCTION__); + hpcalcs_instance_count++; + } + } + + return res; +} + +HPEXPORT int HPCALL hpcalcs_exit(void) { + int res; + if (hpcalcs_instance_count <= 0) { + hpcalcs_error(_("%s: more exits than inits"), __FUNCTION__); + res = ERR_LIBRARY_EXIT; + } + else { + hpcalcs_instance_count--; + + hpcalcs_info(_("%s: exit succeeded"), __FUNCTION__); + res = ERR_SUCCESS; + } + return res; +} + + +HPEXPORT const char* HPCALL hpcalcs_version_get (void) { + return VERSION; +} + + +HPEXPORT uint32_t HPCALL hpcalcs_supported_calcs (void) { + return supported_calcs; +} + + +HPEXPORT calc_handle * HPCALL hpcalcs_handle_new(calc_model model) { + calc_handle * handle = NULL; + if (model < CALC_MAX) { + handle = (calc_handle *)(hpcalcs_alloc_funcs.calloc)(1, sizeof(*handle)); + + if (handle != NULL) { + handle->model = model; + handle->fncts = hpcalcs_all_calcs[model]; + hpcalcs_info("%s: calc handle allocation succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: calc handle allocation failed", __FUNCTION__); + } + } + else { + hpcalcs_error("%s: invalid model", __FUNCTION__); + } + return handle; +} + +HPEXPORT int HPCALL hpcalcs_handle_del(calc_handle * handle) { + int res; + if (handle != NULL) { + if (handle->attached) { + res = hpcalcs_cable_detach(handle); + } + else { + res = ERR_SUCCESS; + } + + (hpcalcs_alloc_funcs.free)(handle->handle); + handle->handle = NULL; + + (hpcalcs_alloc_funcs.free)(handle); + hpcalcs_info("%s: calc handle deletion succeeded", __FUNCTION__); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_cable_attach(calc_handle * handle, cable_handle * cable) { + int res; + if (handle != NULL && cable != NULL) { + res = hpcables_cable_open(cable); + if (res == ERR_SUCCESS) { + handle->cable = cable; + handle->attached = 1; + handle->open = 1; + hpcalcs_info("%s: cable open and attach succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: cable open failed", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_cable_detach(calc_handle * handle) { + int res; + if (handle != NULL) { + res = hpcables_cable_close(handle->cable); + if (res == ERR_SUCCESS) { + handle->open = 0; + handle->attached = 0; + handle->cable = NULL; + hpcalcs_info("%s: cable close and detach succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: cable close and detach failed", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT cable_handle * HPCALL hpcalcs_cable_get(calc_handle * handle) { + cable_handle * res = NULL; + if (handle != NULL) { + res = handle->cable; + hpcalcs_info("%s: cable get succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_handle_display(calc_handle * handle) { + int res; + if (handle != NULL) { + hpcalcs_info("Link calc handle details:"); + hpcalcs_info("\tmodel: %s", hpcalcs_model_to_string(handle->model)); + hpcalcs_info("\tattached: %d", handle->attached); + hpcalcs_info("\topen: %d", handle->open); + hpcalcs_info("\tbusy: %d", handle->busy); + res = ERR_SUCCESS; + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + + return res; +} + +HPEXPORT calc_model HPCALL hpcalcs_get_model(calc_handle * handle) { + calc_model model = CALC_NONE; + if (handle != NULL) { + model = handle->model; + } + else { + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + + return model; +} + + +#define DO_BASIC_HANDLE_CHECKS() \ + if (!handle->attached) { \ + res = ERR_CALC_NO_CABLE; \ + hpcalcs_error("%s: no cable attached", __FUNCTION__); \ + break; \ + } \ + if (!handle->open) { \ + res = ERR_CALC_CABLE_NOT_OPEN; \ + hpcalcs_error("%s: cable not open", __FUNCTION__); \ + break; \ + } \ + if (handle->busy) { \ + res = ERR_CALC_BUSY; \ + hpcalcs_error("%s: cable busy", __FUNCTION__); \ + break; \ + } \ + if (handle->fncts == NULL) { \ + res = ERR_CALC_INVALID_FNCTS; \ + hpcalcs_error("%s: fncts is NULL", __FUNCTION__); \ + break; \ + } + +HPEXPORT int HPCALL hpcalcs_calc_check_ready(calc_handle * handle, uint8_t ** out_data, uint32_t * out_size) { + int res; + if (handle != NULL) { + do { + int (*check_ready) (calc_handle *, uint8_t **, uint32_t *); + + DO_BASIC_HANDLE_CHECKS() + + check_ready = handle->fncts->check_ready; + if (check_ready != NULL) { + handle->busy = 1; + res = (*check_ready)(handle, out_data, out_size); + if (res == ERR_SUCCESS) { + hpcalcs_info("%s: check_ready succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: check_ready failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->check_ready is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_get_infos(calc_handle * handle, calc_infos * infos) { + int res; + if (handle != NULL) { + do { + int (*get_infos) (calc_handle *, calc_infos *); + + DO_BASIC_HANDLE_CHECKS() + + get_infos = handle->fncts->get_infos; + if (get_infos != NULL) { + handle->busy = 1; + res = (*get_infos)(handle, infos); + if (res == 0) { + hpcalcs_info("%s: get_infos succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: get_infos failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->get_infos is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_set_date_time(calc_handle * handle, time_t timestamp) { + int res; + if (handle != NULL) { + do { + int (*set_date_time) (calc_handle *, time_t); + + DO_BASIC_HANDLE_CHECKS() + + set_date_time = handle->fncts->set_date_time; + if (set_date_time != NULL) { + handle->busy = 1; + res = (*set_date_time)(handle, timestamp); + if (res == 0) { + hpcalcs_info("%s: set_date_time succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: set_date_time failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->set_date_time is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_recv_screen(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size) { + int res; + // TODO: some checking on format, but for now, it would hamper documentation efforts. + if (handle != NULL) { + do { + int (*recv_screen) (calc_handle *, calc_screenshot_format, uint8_t **, uint32_t *); + + DO_BASIC_HANDLE_CHECKS() + + recv_screen = handle->fncts->recv_screen; + if (recv_screen != NULL) { + handle->busy = 1; + res = (*recv_screen)(handle, format, out_data, out_size); + if (res == 0) { + hpcalcs_info("%s: recv_screen succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: recv_screen failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->get_infos is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_send_file(calc_handle * handle, files_var_entry * file) { + int res; + if (handle != NULL) { + do { + int (*send_file) (calc_handle *, files_var_entry *); + + DO_BASIC_HANDLE_CHECKS() + + send_file = handle->fncts->send_file; + if (send_file != NULL) { + handle->busy = 1; + res = (*send_file)(handle, file); + if (res == 0) { + hpcalcs_info("%s: send_file succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: send_file failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->send_file is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_recv_file(calc_handle * handle, files_var_entry * name, files_var_entry ** out_file) { + int res; + if (handle != NULL) { + do { + int (*recv_file) (calc_handle *, files_var_entry *, files_var_entry **); + + DO_BASIC_HANDLE_CHECKS() + + recv_file = handle->fncts->recv_file; + if (recv_file != NULL) { + handle->busy = 1; + res = (*recv_file)(handle, name, out_file); + if (res == 0) { + hpcalcs_info("%s: recv_file succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: recv_file failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->recv_file is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_recv_backup(calc_handle * handle, files_var_entry *** out_vars) { + int res; + if (handle != NULL) { + do { + int (*recv_backup) (calc_handle *, files_var_entry ***); + + DO_BASIC_HANDLE_CHECKS() + + recv_backup = handle->fncts->recv_backup; + if (recv_backup != NULL) { + handle->busy = 1; + res = (*recv_backup)(handle, out_vars); + if (res == 0) { + hpcalcs_info("%s: recv_backup succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: recv_backup failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->recv_backup is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_send_key(calc_handle * handle, uint32_t code) { + int res; + if (handle != NULL) { + do { + int (*send_key) (calc_handle *, uint32_t); + + DO_BASIC_HANDLE_CHECKS() + + send_key = handle->fncts->send_key; + if (send_key != NULL) { + handle->busy = 1; + res = (*send_key)(handle, code); + if (res == 0) { + hpcalcs_info("%s: send_key succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: send_key failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->send_key is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_send_keys(calc_handle * handle, const uint8_t * data, uint32_t size) { + int res = -1; + if (handle != NULL) { + do { + int (*send_keys) (calc_handle *, const uint8_t *, uint32_t); + + DO_BASIC_HANDLE_CHECKS() + + send_keys = handle->fncts->send_keys; + if (send_keys != NULL) { + handle->busy = 1; + res = (*send_keys)(handle, data, size); + if (res == 0) { + hpcalcs_info("%s: send_keys succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: send_keys failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->send_keys is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_send_chat(calc_handle * handle, const uint16_t * data, uint32_t size) { + int res; + if (handle != NULL) { + do { + int (*send_chat) (calc_handle *, const uint16_t *, uint32_t); + + DO_BASIC_HANDLE_CHECKS() + + send_chat = handle->fncts->send_chat; + if (send_chat != NULL) { + handle->busy = 1; + res = (*send_chat)(handle, data, size); + if (res == 0) { + hpcalcs_info("%s: send_chat succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: send_chat failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->send_chat is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL hpcalcs_calc_recv_chat(calc_handle * handle, uint16_t ** data, uint32_t *size) { + int res; + if (handle != NULL) { + do { + int (*recv_chat) (calc_handle *, uint16_t **, uint32_t *); + + DO_BASIC_HANDLE_CHECKS() + + recv_chat = handle->fncts->recv_chat; + if (recv_chat != NULL) { + handle->busy = 1; + res = (*recv_chat)(handle, data, size); + if (res == 0) { + hpcalcs_info("%s: recv_chat succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: recv_chat failed", __FUNCTION__); + } + handle->busy = 0; + } + else { + res = ERR_CALC_INVALID_FNCTS; + hpcalcs_error("%s: fncts->recv_chat is NULL", __FUNCTION__); + } + } while (0); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +#undef DO_BASIC_HANDLE_CHECKS + +HPEXPORT int HPCALL hpcalcs_probe_calc(cable_model cable, calc_model * out_calc) { + int res; + if (out_calc != NULL) { + if (cable == CABLE_PRIME_HID) { + res = ERR_SUCCESS; + *out_calc = CALC_PRIME; + hpcalcs_info("%s: calc probe succeeded", __FUNCTION__); + } + else { + res = ERR_CALC_PROBE_FAILED; + hpcalcs_error("%s: calc probe failed", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: out_calc is NULL", __FUNCTION__); + } + return res; +} diff --git a/libhpcalcs/src/hpcalcs.h b/libhpcalcs/src/hpcalcs.h new file mode 100644 index 0000000..90f4f22 --- /dev/null +++ b/libhpcalcs/src/hpcalcs.h @@ -0,0 +1,424 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpcalcs.h Calcs: base part. + */ + +#ifndef __HPLIBS_CALCS_H__ +#define __HPLIBS_CALCS_H__ + +#include +#include +#include + +#include "hplibs.h" +#include "hpfiles.h" +#include "hpcables.h" + +//! Opaque type for internal _calc_fncts. +typedef struct _calc_fncts calc_fncts; +//! Opaque type for internal _calc_handle. +typedef struct _calc_handle calc_handle; + +//! Indices of the function pointers in _calc_fncts. +typedef enum { + CALC_FNCT_CHECK_READY = 0, + CALC_FNCT_GET_INFOS = 1, + CALC_FNCT_SET_DATE_TIME = 2, + CALC_FNCT_RECV_SCREEN = 3, + CALC_FNCT_SEND_FILE = 4, + CALC_FNCT_RECV_FILE = 5, + CALC_FNCT_RECV_BACKUP = 6, + CALC_FNCT_SEND_KEY = 7, + CALC_FNCT_SEND_KEYS = 8, + CALC_FNCT_SEND_CHAT = 9, + CALC_FNCT_RECV_CHAT = 10, + CALC_FNCT_LAST ///< Keep this one last +} calc_fncts_idx; + +//! Used in the bit field of _calc_fncts, indicating whether a given calculator supports a given operation. +typedef enum { + CALC_OPS_NONE = 0, + CALC_OPS_CHECK_READY = (1 << CALC_FNCT_CHECK_READY), + CALC_OPS_GET_INFOS = (1 << CALC_FNCT_GET_INFOS), + CALC_OPS_SET_DATE_TIME = (1 << CALC_FNCT_SET_DATE_TIME), + CALC_OPS_RECV_SCREEN = (1 << CALC_FNCT_RECV_SCREEN), + CALC_OPS_SEND_FILE = (1 << CALC_FNCT_SEND_FILE), + CALC_OPS_RECV_FILE = (1 << CALC_FNCT_RECV_FILE), + CALC_OPS_RECV_BACKUP = (1 << CALC_FNCT_RECV_BACKUP), + CALC_OPS_SEND_KEY = (1 << CALC_FNCT_SEND_KEY), + CALC_OPS_SEND_KEYS = (1 << CALC_FNCT_SEND_KEYS), + CALC_OPS_SEND_CHAT = (1 << CALC_FNCT_SEND_CHAT), + CALC_OPS_RECV_CHAT = (1 << CALC_FNCT_RECV_CHAT) +} calc_features_operations; + +//! Screenshot formats supported by the calculators, list is known to be incomplete. +typedef enum { + // 5 is triggered periodically by the official connectivity kit. It returns something with a PNG header, but much smaller. + CALC_SCREENSHOT_FORMAT_FIRST = 8, + CALC_SCREENSHOT_FORMAT_PRIME_PNG_320x240x16 = 8, + CALC_SCREENSHOT_FORMAT_PRIME_PNG_320x240x4 = 9, + CALC_SCREENSHOT_FORMAT_PRIME_PNG_160x120x16 = 10, + CALC_SCREENSHOT_FORMAT_PRIME_PNG_160x120x4 = 11, + CALC_SCREENSHOT_FORMAT_LAST ///< Keep this one last +} calc_screenshot_format; + +//! Structure containing information returned by the calculator. This will change a lot when the returned data is better documented. +typedef struct { + uint32_t size; + uint8_t * data; +} calc_infos; + +//! Internal structure containing information about the calculator, and function pointers. +struct _calc_fncts { + calc_model model; + const char * name; + const char * description; + int features; + int (*check_ready) (calc_handle * handle, uint8_t ** out_data, uint32_t * out_size); + int (*get_infos) (calc_handle * handle, calc_infos * infos); + int (*set_date_time) (calc_handle * handle, time_t timestamp); + int (*recv_screen) (calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); + int (*send_file) (calc_handle * handle, files_var_entry * file); + int (*recv_file) (calc_handle * handle, files_var_entry * request, files_var_entry ** out_file); + int (*recv_backup) (calc_handle * handle, files_var_entry *** out_vars); + int (*send_key) (calc_handle * handle, uint32_t code); + int (*send_keys) (calc_handle * handle, const uint8_t * data, uint32_t size); + int (*send_chat) (calc_handle * handle, const uint16_t * data, uint32_t size); + int (*recv_chat) (calc_handle * handle, uint16_t ** out_data, uint32_t * out_size); +}; + +//! Internal structure containing state about the calculator, returned and passed around by the user. +struct _calc_handle { + calc_model model; + void * handle; + const calc_fncts * fncts; + cable_handle * cable; + int attached; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. + int open; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. + int busy; // Should be made explicitly atomic with GCC >= 4.7 or Clang, but int is atomic on most ISAs anyway. +}; + + +//! Structure passed to \a hpcalcs_init, contains e.g. callbacks for logging and memory allocation. +typedef struct { + unsigned int version; ///< Config version number. + void (*log_callback)(const char *format, va_list args); ///< Callback function for receiving logging output. + hplibs_malloc_funcs * alloc_funcs; ///< Function pointers used for dynamic memory allocation. If NULL, the library defaults to malloc(), calloc(), realloc(), free(). +} hpcalcs_config; + +//! Latest revision of the \a hpcalcs_config struct layout supported by this version of the library. +#define HPCALCS_CONFIG_VERSION (1) + + +//! Structure defining a raw packet for the Prime, used at the lowest layer of the protocol implementation. +typedef struct +{ + uint32_t size; + uint8_t data[PRIME_RAW_HID_DATA_SIZE + 1]; +} prime_raw_hid_pkt; + + +//! Structure defining a virtual packet for the Prime, used at the middle layer of the protocol implementation (fragmented to / reassembled from raw packets). +typedef struct +{ + uint32_t size; + uint8_t * data; + uint8_t cmd; +} prime_vtl_pkt; + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initializes library internals. Must be called before any other libhpcalcs function. + * \param config pointer to struct containing e.g. callbacks passed to the library. + * \return Whether the initialization succeeded. + * \note the contents of alloc_funcs are copied. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpcalcs_init(hpcalcs_config * config); +/** + * \brief Tears down library internals. No other libhpcalcs function can be called after this one. + * \return Whether the teardown succeeded. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpcalcs_exit(void); + +/** + * \brief Returns the library version string. + * \return The library version string, usually under the form "X.Y.Z". + **/ +HPEXPORT const char* HPCALL hpcalcs_version_get(void); + +/** + * \brief Returns the calcs supported by the current build of the library. + * \return An integer containing a binary OR of (1 << CALC_*) values, where CALC_* values are defined in enum \a calc_model. + **/ +HPEXPORT uint32_t HPCALL hpcalcs_supported_calcs(void); + +/** + * \brief Gets the error message if the error was produced by this library + * \param number the error number (from internal error.h) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * \note the string is allocated with malloc(), therefore it must be freed with free(). + * \return 0 if the error was produced by this library, otherwise the error number (for propagation). + **/ +HPEXPORT int HPCALL hpcalcs_error_get(int number, char **message); + +/** + * \brief Sets the callback function used by the library for logging + * \param log_callback function pointer + */ +HPEXPORT void HPCALL hpcalcs_log_set_callback(void (*log_callback)(const char *format, va_list args)); +/** + * \brief Sets the log level of the library, for controlling how much logging output is produced. + * \param log_level log level (from hplibs.h) + * \return the previous log level + */ +HPEXPORT hplibs_logging_level HPCALL hpcalcs_log_set_level(hplibs_logging_level log_level); + + +/** + * \brief Create a new handle (opaque structure) for the given calc model. + * The handle must be freed with \a hpcalcs_handle_del when no longer needed. + * \param model the calculator model. + * \return NULL if an error occurred, otherwise a valid handle. + **/ +HPEXPORT calc_handle * HPCALL hpcalcs_handle_new(calc_model model); +/** + * \brief Deletes a handle (opaque structure) created by \a hpcalcs_handle_new(). + * \param handle the handle to be deleted. + * \return 0 if the deletion succeeded, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcalcs_handle_del(calc_handle * handle); +/** + * \brief Shows basic information about a handle + * \param handle the handle to be dumped. + * \return 0 if the handle was non-NULL, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcalcs_handle_display(calc_handle * handle); + +/** + * \brief Retrieves the calc model from the given calc handle. + * \param handle the calc handle + * \return the calc model corresponding to the given handle. + */ +HPEXPORT calc_model HPCALL hpcalcs_get_model(calc_handle * handle); + +/** + * \brief Opens and attaches the given cable for use with the given calculator. + * \param handle the calculator handle. + * \param cable the cable handle. + * \return 0 upon success, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcalcs_cable_attach(calc_handle * handle, cable_handle * cable); +/** + * \brief Closes and detaches the cable attached to the given calculator handle. + * \param handle the calculator handle. + * \return 0 upon success, nonzero otherwise. + **/ +HPEXPORT int HPCALL hpcalcs_cable_detach(calc_handle * handle); +/** + * \brief Retrieves the cable handle attached to the given calculator handle, if any. + * \param handle the calculator handle. + * \return NULL if an error occurred, otherwise a cable handle. + **/ +HPEXPORT cable_handle * HPCALL hpcalcs_cable_get(calc_handle * handle); + +/** + * \brief Checks whether the calculator is ready + * \param handle the calculator handle. + * \param out_data storage area for information contained in the calculator's reply. + * \param out_size storage area for size of the information contained in the calculator's reply. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_check_ready(calc_handle * handle, uint8_t ** out_data, uint32_t * out_size); +/** + * \brief Retrieves some information, such as firmware version, from the calculator. + * \param handle the calculator handle. + * \param infos storage area for information contained in the reply. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_get_infos(calc_handle * handle, calc_infos * infos); +/** + * \brief Sets the calculator's date and time from a standard C89 / *nix timestamp. + * \param handle the calculator handle. + * \param timestamp the timestamp since the Epoch (1970). + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_set_date_time(calc_handle * handle, time_t timestamp); +/** + * \brief Retrieves a screenshot from the calculator + * \param handle the calculator handle. + * \param format the desired screenshot format. + * \param out_data storage area for screenshot contained in the calculator's reply. + * \param out_size storage area for size of the screenshot contained in the calculator's reply. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_recv_screen(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); +/** + * \brief Sends a file to the calculator. + * \param handle the calculator handle. + * \param file information about the file to be sent. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_send_file(calc_handle * handle, files_var_entry * file); +/** + * \brief Receives a file from the calculator. + * \param handle the calculator handle. + * \param request information about the file to be received. + * \param out_file storage area for the file to be received. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_recv_file(calc_handle * handle, files_var_entry * request, files_var_entry ** out_file); +/** + * \brief Receives a backup (made of multiple files) from the calculator. + * \param handle the calculator handle. + * \param out_vars storage area for the files to be received. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_recv_backup(calc_handle * handle, files_var_entry *** out_vars); +/** + * \brief Sends a single keypress to the calculator. + * \param handle the calculator handle. + * \param code the key code. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_send_key(calc_handle * handle, uint32_t code); +/** + * \brief Sends potentially multiple keypresses to the calculator. + * \param handle the calculator handle. + * \param data the buffer containings key codes. + * \param size the size of the data in the buffer. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_send_keys(calc_handle * handle, const uint8_t * data, uint32_t size); +/** + * \brief Sends chat data to the calculator. + * \param handle the calculator handle. + * \param data the data to be sent (UTF-16LE string, with U+0000 terminator, without UTF-16 LE BOM). + * \param size the size of the data to be sent. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_send_chat(calc_handle * handle, const uint16_t * data, uint32_t size); +/** + * \brief Receives chat data from the calculator. + * \param handle the calculator handle. + * \param out_data storage area for the chat data contained in the calculator's reply. + * \param out_size storage area for size of the chat data contained in the calculator's reply. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpcalcs_calc_recv_chat(calc_handle * handle, uint16_t ** out_data, uint32_t * out_size); + + +/** + * \brief Sends the given raw packet to the Prime calculator using given calculator handle. + * \param handle the calculator handle. + * \param pkt the raw packet. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_send(calc_handle * handle, prime_raw_hid_pkt * pkt); +/** + * \brief Receives a raw packet from the Prime calculator using given calculator handle, and store the result to given packet. + * \param handle the calculator handle. + * \param pkt the dest raw packet. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_recv(calc_handle * handle, prime_raw_hid_pkt * pkt); + +/** + * \brief Probes the given cable model to find out what calculator is connected to it. + * \param cable the cable model to be probed. + * \param out_calc storage area for the calculator model attached to the cable (if any). + * \return 0 upon success, nonzero otherwise. + * \note For now, the calculator type is fully determined by the calculator type. This might change in the future. + */ +HPEXPORT int HPCALL hpcalcs_probe_calc(cable_model cable, calc_model * out_calc); + + +/** + * \brief Creates a virtual packet for the Prime calculator, preallocating the given size. + * \param size the size to be preallocated. + * \return NULL if an error occurred, a virtual packet otherwise. + */ +HPEXPORT prime_vtl_pkt * HPCALL prime_vtl_pkt_new(uint32_t size); +/** + * \brief Creates a virtual packet for the Prime calculator, filling it with the given size and data. + * \param size the size of the data. + * \param data the pre-allocated data (assumed to be allocated with the same memory allocator as the one given to libhpcalcs, if not using the default one). + * \return NULL if an error occurred, a virtual packet otherwise. + * \warning This function takes ownership of \a data. + */ +HPEXPORT prime_vtl_pkt * HPCALL prime_vtl_pkt_new_with_data_ptr(uint32_t size, uint8_t * data); +/** + * \brief Deletes a virtual packet for the Prime calculator. + * \param pkt the packet to be deleted. + */ +HPEXPORT void HPCALL prime_vtl_pkt_del(prime_vtl_pkt * pkt); + +/** + * \brief Sends the given virtual packet to the Prime calculator using given calculator handle. + * \param handle the calculator handle. + * \param pkt the virtual packet. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_send_data(calc_handle * handle, prime_vtl_pkt * pkt); +/** + * \brief Receives a virtual packet from the Prime calculator using given calculator handle, and store the result to given packet. + * \param handle the calculator handle. + * \param pkt the dest virtual packet. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_recv_data(calc_handle * handle, prime_vtl_pkt * pkt); +/** + * \brief Returns the packet size corresponding to command \a cmd, possibly corrected by the contents of \a data. + * \param cmd the command. + * \param data the data. + * \param size storage area for size of the data. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL prime_data_size(uint8_t cmd, uint8_t * data, uint32_t * out_size); + + +/** + * \brief Converts a calculator model to a printable string. + * \param model the calculator model. + * \return the string corresponding to the calculator model. + **/ +HPEXPORT const char * HPCALL hpcalcs_model_to_string(calc_model model); +/** + * \brief Converts a string to a supported calculator model, if possible. + * \param str the string. + * \return the calculator model corresponding to the string, CALC_NONE if failed. + **/ +HPEXPORT calc_model HPCALL hpcalcs_string_to_model(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libhpcalcs/src/hpfiles.c b/libhpcalcs/src/hpfiles.c new file mode 100644 index 0000000..7198a4e --- /dev/null +++ b/libhpcalcs/src/hpfiles.c @@ -0,0 +1,378 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpfiles.c Files: base part. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include +#include + +#include +#include "internal.h" +#include "logging.h" +#include "error.h" +#include "utils.h" +#include "gettext.h" + +hplibs_malloc_funcs hpfiles_alloc_funcs = { + .malloc = malloc, + .calloc = calloc, + .realloc = realloc, + .free = free +}; + + +// not static, must be shared between instances +int hpfiles_instance_count = 0; + +HPEXPORT int HPCALL hpfiles_init(hpfiles_config * config) { + int res = ERR_SUCCESS; + void (*log_callback)(const char *format, va_list args); + hplibs_malloc_funcs * alloc_funcs; + + if (config == NULL) { + log_callback = NULL; + alloc_funcs = NULL; + } + else { + if (config->version <= HPFILES_CONFIG_VERSION) { + if (config->version == 1) { + log_callback = config->log_callback; + alloc_funcs = config->alloc_funcs; + } + else { + hpcables_error(_("%s: unsupported config version %u"), __FUNCTION__, config->version); + res = ERR_LIBRARY_CONFIG_VERSION; + } + } + else { + hpcables_error(_("%s: unsupported config version %u"), __FUNCTION__, config->version); + res = ERR_LIBRARY_CONFIG_VERSION; + } + } + + if (!res) { + // Set up locale info, if NLS support is enabled. +#ifdef ENABLE_NLS + { + char locale_dir[65536]; + +#ifdef __WIN32__ + HANDLE hDll; + int i; + + hDll = GetModuleHandle("libhpcalcs-0.dll"); + GetModuleFileName(hDll, locale_dir, 65515); + + for (i = (int)strlen(locale_dir); i >= 0; i--) { + if (locale_dir[i] == '\\') { + break; + } + } + locale_dir[i] = '\0'; + + strcat(locale_dir, "\\locale"); +#else + strncpy(locale_dir, LOCALEDIR, sizeof(locale_dir) - 21); +#endif + + hpfiles_info("setlocale: %s", setlocale(LC_ALL, "")); + hpfiles_info("bindtextdomain: %s", bindtextdomain(PACKAGE, locale_dir)); + bind_textdomain_codeset(PACKAGE, "UTF-8"/*"ISO-8859-15"*/); + hpfiles_info("textdomain: %s", textdomain(NULL)); + } +#endif + + if (!hpfiles_instance_count) { + hpfiles_log_set_callback(log_callback); + if (alloc_funcs != NULL) { + hpfiles_alloc_funcs = *alloc_funcs; + } + hpfiles_info(_("hpfiles library version %s"), hpfiles_version_get()); + + hpfiles_info(_("%s: init succeeded"), __FUNCTION__); + hpfiles_instance_count++; + } + else { + hpfiles_info(_("%s: re-init skipped"), __FUNCTION__); + hpfiles_instance_count++; + } + } + + return res; +} + +HPEXPORT int HPCALL hpfiles_exit(void) { + int res; + if (hpfiles_instance_count <= 0) { + hpfiles_error(_("%s: more exits than inits"), __FUNCTION__); + res = ERR_LIBRARY_EXIT; + } + else { + hpfiles_instance_count--; + + hpfiles_info(_("%s: exit succeeded"), __FUNCTION__); + res = ERR_SUCCESS; + } + return res; +} + + +HPEXPORT const char* HPCALL hpfiles_version_get (void) { + return VERSION; +} + + +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create(void) { + return (hpfiles_alloc_funcs.calloc)(1, sizeof(files_var_entry)); +} + +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_size(uint32_t size) { + files_var_entry * ve = hpfiles_ve_create(); + if (ve != NULL) { + ve->data = (uint8_t *)(hpfiles_alloc_funcs.calloc)(sizeof(uint8_t), size); + if (ve->data != NULL) { + ve->size = size; + } + else { + (hpfiles_alloc_funcs.free)(ve); + ve = NULL; + } + } + + if (ve == NULL) { + hpfiles_error("%s: failed to create ve", __FUNCTION__); + } + + return ve; +} + +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_data(uint8_t * data, uint32_t size) { + files_var_entry * ve = hpfiles_ve_create(); + if (ve != NULL) { + ve->data = (uint8_t *)(hpfiles_alloc_funcs.malloc)(size); + if (ve->data != NULL) { + if (data != NULL) { + memcpy(ve->data, data, size); + } + ve->size = size; + } + else { + (hpfiles_alloc_funcs.free)(ve); + ve = NULL; + } + } + + if (ve == NULL) { + hpfiles_error("%s: failed to create ve", __FUNCTION__); + } + + return ve; +} + +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_data_ptr(uint8_t * data, uint32_t size) { + files_var_entry * ve = hpfiles_ve_create(); + if (ve != NULL) { + ve->data = data; + ve->size = size; + } + else { + hpfiles_error("%s: failed to create ve", __FUNCTION__); + } + + return ve; +} + +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_data_and_name(uint8_t * data, uint32_t size, const char16_t * name) { + files_var_entry * ve = hpfiles_ve_create_with_data(data, size); + if (ve != NULL) { + char16_strncpy(ve->name, name, FILES_VARNAME_MAXLEN); + } + + if (ve == NULL) { + hpfiles_error("%s: failed to create ve", __FUNCTION__); + } + + return ve; +} + +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_from_file(FILE * file, const char16_t * filename) { + files_var_entry * ve = NULL; + if (file != NULL) { + if (!fseek(file, 0, SEEK_END)) { + long size = ftell(file); + if (size != -1) { + if (!fseek(file, 0, SEEK_END)) { + // No calculator has 4 GB memory, let alone handle 4 GB variables, so let's (potentially) truncate long to uint32_t. + ve = hpfiles_ve_create_with_size((uint32_t)size); + if (ve != NULL) { + if (fread(ve->data, 1, (uint32_t)size, file) == (uint32_t)size) { + char16_strncpy(ve->name, filename, FILES_VARNAME_MAXLEN); + } + else { + hpfiles_error("%s: couldn't read from file", __FUNCTION__); + } + } + // else fall through + } + else { + hpfiles_error("%s: couldn't seek to BOF", __FUNCTION__); + } + } + else { + hpfiles_error("%s: couldn't obtain file size", __FUNCTION__); + } + } + else { + hpfiles_error("%s: couldn't seek to EOF", __FUNCTION__); + } + } + else { + hpfiles_error("%s: file is NULL", __FUNCTION__); + } + + if (ve == NULL) { + hpfiles_error("%s: failed to create ve", __FUNCTION__); + } + + return ve; +} + +HPEXPORT void HPCALL hpfiles_ve_delete(files_var_entry * ve) { + if (ve != NULL) { + (hpfiles_alloc_funcs.free)(ve->data); + (hpfiles_alloc_funcs.free)(ve); + } + else { + hpfiles_error("%s: ve is NULL", __FUNCTION__); + } +} + + +HPEXPORT void *hpfiles_ve_alloc_data(uint32_t size) { + return (hpfiles_alloc_funcs.calloc)(sizeof(uint8_t), size + 1); +} + +HPEXPORT files_var_entry * HPCALL hpfiles_ve_copy(files_var_entry * dst, files_var_entry * src) { + if (src != NULL && dst != NULL) { + memcpy(dst, src, sizeof(files_var_entry)); + if (src->data != NULL) { + dst->data = (uint8_t *)(hpfiles_alloc_funcs.malloc)(src->size); + if (dst->data != NULL) { + memcpy(dst->data, src->data, src->size); + } + else { + dst = NULL; + } + } + } + else { + hpfiles_error("%s: an argument is NULL", __FUNCTION__); + dst = NULL; + } + + return dst; +} + +HPEXPORT files_var_entry * HPCALL hpfiles_ve_dup(files_var_entry * src) { + files_var_entry * dst = NULL; + + if (src != NULL) { + dst = (hpfiles_alloc_funcs.malloc)(sizeof(files_var_entry)); + if (dst != NULL) { + memcpy(dst, src, sizeof(files_var_entry)); + if (src->data != NULL) { + dst->data = (uint8_t *)(hpfiles_alloc_funcs.malloc)(src->size); + if (dst->data != NULL) { + memcpy(dst->data, src->data, src->size); + } + else { + (hpfiles_alloc_funcs.free)(dst); + dst = NULL; + } + } + } + } + else { + hpfiles_error("%s: src is NULL", __FUNCTION__); + } + + if (dst == NULL) { + hpfiles_error("%s: failed to create ve", __FUNCTION__); + } + + return dst; +} + + +HPEXPORT int hpfiles_ve_display(files_var_entry * ve) { + int res; + if (ve != NULL) { + hpfiles_info("Displaying var entry %p", ve); + hpfiles_info("Name: %ls", ve->name); + hpfiles_info("Model: %u (%02X)", ve->model, ve->model); + hpfiles_info("Type: %u (%02X)", ve->type, ve->type); + hpfiles_info("Invalid: %u", ve->invalid); + hpfiles_info("Size: %" PRIu32 " (%02" PRIX32 ")", ve->size, ve->size); + hpfiles_info("Data: %p", ve->data); + res = ERR_SUCCESS; + } + else { + res = ERR_INVALID_PARAMETER; + hpfiles_error("%s: ve is NULL", __FUNCTION__); + } + return res; +} + + +HPEXPORT files_var_entry ** HPCALL hpfiles_ve_create_array(uint32_t element_count) { + return (files_var_entry **)(hpfiles_alloc_funcs.calloc)(element_count + 1, sizeof(files_var_entry *)); +} + +HPEXPORT files_var_entry ** HPCALL hpfiles_ve_resize_array(files_var_entry ** array, uint32_t element_count) { + return (files_var_entry **)(hpfiles_alloc_funcs.realloc)(array, (element_count + 1) * sizeof(files_var_entry *)); +} + +HPEXPORT void HPCALL hpfiles_ve_delete_array(files_var_entry ** array) { + + if (array != NULL) { + files_var_entry ** ptr; + for (ptr = array; *ptr; ptr++) { + hpfiles_ve_delete(*ptr); + } + (hpfiles_alloc_funcs.free)(array); + } + else { + hpfiles_error("%s: array is NULL", __FUNCTION__); + } +} diff --git a/libhpcalcs/src/hpfiles.h b/libhpcalcs/src/hpfiles.h new file mode 100644 index 0000000..ad7aa50 --- /dev/null +++ b/libhpcalcs/src/hpfiles.h @@ -0,0 +1,283 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpfiles.h Files: base part. + */ + +#ifndef __HPLIBS_FILES_H__ +#define __HPLIBS_FILES_H__ + +#include +#include +#include +#include + +// As of 2013/11, too many environments still don't support . +// Since the only thing from this header libhpfiles uses (for now) is char16_t: +// * on modern GCC and Clang (the main targets of this code base), use the builtin __CHAR16_TYPE__ preprocessor define; +// * otherwise, fall back to uint16_t. +#ifdef __CHAR16_TYPE__ +typedef __CHAR16_TYPE__ char16_t; +#else +typedef uint16_t char16_t; +#endif + +#include "hplibs.h" +#include "filetypes.h" + +//! Maximum length of a variable name for the calculators supported by libhpfiles. +// Not sure the target calculators even support such long filenames... +#define FILES_VARNAME_MAXLEN 128 + +//! Generic structure for storing the contents of a variable, or requesting that a variable be sent. +typedef struct +{ + char16_t name[FILES_VARNAME_MAXLEN+1]; + + uint8_t type; + uint8_t model; + uint8_t invalid; ///< Set to nonzero by e.g. hpcalcs_calc_recv_file() if a packet loss was detected. + uint32_t size; + uint8_t* data; +} files_var_entry; + + +//! Structure passed to \a hpfiles_init, contains e.g. callbacks for logging and memory allocation. +typedef struct { + unsigned int version; ///< Config version number. + void (*log_callback)(const char *format, va_list args); ///< Callback function for receiving logging output. + hplibs_malloc_funcs * alloc_funcs; ///< Function pointers used for dynamic memory allocation. If NULL, the library defaults to malloc(), calloc(), realloc(), free(). +} hpfiles_config; + +//! Latest revision of the \a hpfiles_config struct layout supported by this version of the library. +#define HPFILES_CONFIG_VERSION (1) + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initializes library internals. Must be called before any other libhpfiles function. + * \param config pointer to struct containing e.g. callbacks passed to the library. + * \return Whether the initialization succeeded. + * \note the contents of alloc_funcs are copied. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpfiles_init(hpfiles_config * config); +/** + * \brief Tears down library internals. No other libhpfiles function can be called after this one. + * \return Whether the teardown succeeded. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpfiles_exit(void); + +/** + * \brief Returns the library version string. + * \return The library version string, usually under the form "X.Y.Z". + **/ +HPEXPORT const char* HPCALL hpfiles_version_get(void); + +/** + * \brief Gets the error message if the error was produced by this library + * \param number the error number (from internal error.h) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * \note the string is allocated with malloc(), therefore it must be freed with free(). + * \return 0 if the error was produced by this library, otherwise the error number (for propagation). + **/ +HPEXPORT int HPCALL hpfiles_error_get(int number, char **message); + +/** + * \brief Sets the callback function used by the library for logging + * \param log_callback function pointer + */ +HPEXPORT void HPCALL hpfiles_log_set_callback(void (*log_callback)(const char *format, va_list args)); +/** + * \brief Sets the log level of the library, for controlling how much logging output is produced. + * \param log_level log level (from hplibs.h) + * \return the previous log level + */ +HPEXPORT hplibs_logging_level HPCALL hpfiles_log_set_level(hplibs_logging_level log_level); + + +/** + * \brief Creates an empty files_var_entry structure. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create(void); +/** + * \brief Creates and preallocates a files_var_entry structure. + * \param size the size to be allocated. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_size(uint32_t size); +/** + * \brief Creates and fills a files_var_entry structure with the given data. + * \param data the data to be duplicated. + * \param size the size of the data. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_data(uint8_t * data, uint32_t size); +/** + * \brief Creates and fills a files_var_entry structure with the given preallocated data. + * \param data the data to be attached to the files_var_entry (assumed to be allocated with the same memory allocator as the one given to libhpfiles, if not using the default one). + * \param size the size of the data. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_data_ptr(uint8_t * data, uint32_t size); +/** + * \brief Creates and fills a files_var_entry structure with the given data. + * \param data the data to be copied + * \param size the size of the data. + * \param name the file name on the calculator side. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_with_data_and_name(uint8_t * data, uint32_t size, const char16_t * name); +/** + * \brief Creates and fills a files_var_entry structure from the given file, if it exists. + * \param file the FILE pointer to be used for filling in a files_var_entry instance. + * \param filename the UTF-16LE name of the file on the calculator side, can be NULL if you want to set it later. + * \return Pointer to files_var_entry, NULL if failed. + */ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_create_from_file(FILE * file, const char16_t * filename); +/** + * \brief Destroys the given files_var_entry instance (embedded data + the entry itself). + * \param entry the entry + */ +HPEXPORT void HPCALL hpfiles_ve_delete(files_var_entry * entry); + +/** + * \brief Allocates data for the \a data field of files_var_entry. + * \param size the size to be allocated + * \return Pointer to allocated data, NULL if failed. + */ +HPEXPORT void * HPCALL hpfiles_ve_alloc_data(uint32_t size); +/** + * \brief Copies files_var_entry and its content (if any) from pre-existing src to pre-existing dst. + * \param dst destination entry. + * \param src source entry. + * \return dst, NULL if failed. + **/ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_copy(files_var_entry * dst, files_var_entry * src); +/** + * \brief Duplicates files_var_entry and its content (if any) by creating a new instance. + * \param src source entry + * \return The new entry, NULL if failed. + **/ +HPEXPORT files_var_entry * HPCALL hpfiles_ve_dup(files_var_entry * src); + +/** + * \brief Shows basic information about a variable entry + * \param entry the entry to be dumped. + * \return 0 if the handle was non-NULL, nonzero otherwise. + **/ +HPEXPORT int hpfiles_ve_display(files_var_entry * entry); + +/** + * \brief Creates a NULL-terminated array for storing the given number of potentially non-NULL files_var_entry pointers. + * \param element_count the number of pointers + * \return The new array containing element_count + 1 NULL pointers, NULL if failed. + **/ +HPEXPORT files_var_entry ** HPCALL hpfiles_ve_create_array(uint32_t element_count); +/** + * \brief Reallocates a NULL-terminated array for storing a new number of potentially non-NULL files_var_entry pointers. + * \param entries the array of entries. + * \param element_count the new number of pointers + * \return The new array containing element_count + 1 pointers, NULL if failed. + * \note If the array was enlarged, the new storage space isn't cleared. + **/ +HPEXPORT files_var_entry ** HPCALL hpfiles_ve_resize_array(files_var_entry ** entries, uint32_t element_count); +/** + * \brief Destroys the whole array of files_var_entry structs (including the structures themselves and their embedded data). + * \param entries the array to be destroyed. + **/ +HPEXPORT void HPCALL hpfiles_ve_delete_array(files_var_entry ** entries); + + +/** + * \brief Converts a calculator model to a printable string. + * \param model the calculator model. + * \return the string corresponding to the calculator model. + **/ +HPEXPORT const char * HPCALL hpfiles_model_to_string(calc_model model); +/** + * \brief Converts a string to a supported calculator model, if possible. + * \param str the string. + * \return the calculator model corresponding to the string, CALC_NONE if failed. + **/ +HPEXPORT calc_model HPCALL hpfiles_string_to_model(const char *str); + +/** + * \brief Converts a file type ID to a printable file type string, according to the given calculator model. + * \param model the calculator model + * \param type the file type ID + * \return the file type string corresponding to the given type ID, if any. + */ +HPEXPORT const char * HPCALL hpfiles_vartype2str(calc_model model, uint8_t type); +/** + * \brief Converts a file type (under string form) to a file type ID, according to the given calculator model. + * \param model the calculator model + * \param type the file type string + * \return the file type ID corresponding to the given type string, if any. + */ +HPEXPORT uint8_t HPCALL hpfiles_str2vartype(calc_model model, const char * type); +/** + * \brief Converts a file type to an extension, according to the given calculator model. + * \param model the calculator model + * \param type the file type ID + * \return the file extension corresponding to the given type, if any. + * \note may have to use char16_t instead of char... + */ +HPEXPORT const char * HPCALL hpfiles_vartype2fext(calc_model model, uint8_t type); +/** + * \brief Converts a file extension to a file type ID, according to the given calculator model. + * \param model the calculator model + * \param type the file type as string. + * \return the file type ID corresponding to the given extension, if any. + */ +HPEXPORT uint8_t HPCALL hpfiles_fext2vartype(calc_model model, const char * type); +/** + * \brief Converts a file path to a file type ID, according to the given calculator model. + * \param model the calculator model + * \param filepath the file path as string. + * \return the file type ID corresponding to the given file, if any. + */ +HPEXPORT uint8_t HPCALL hpfiles_filename2vartype(calc_model model, const char * filepath); +/** + * \brief Interprets a file path to a file type ID + calculator-side file name, according to the given calculator model. + * \param model the calculator model + * \param filepath the file path as string. + * \param out_type storage space for the file type ID corresponding to the given file, if any. + * \param out_calcfilename a dynamically allocated string containing the calculator-side filename (usually stripped from the computer-side file extension). + * \return 0 if parsing succeeded, nonzero otherwise. + * \note may have to use char16_t instead of char... + * \note the string is allocated with malloc(), therefore it must be freed with free(). + */ +HPEXPORT int HPCALL hpfiles_parsefilename(calc_model model, const char * filepath, uint8_t * out_type, char ** out_calcfilename); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libhpcalcs/src/hplibs.h b/libhpcalcs/src/hplibs.h new file mode 100644 index 0000000..254d66c --- /dev/null +++ b/libhpcalcs/src/hplibs.h @@ -0,0 +1,93 @@ +/* + * libhpfiles, libhpcables, libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hplibs.h Files, Cables, Calcs: definitions common to libhpfiles, libhpcables, libhpcalcs. + */ + +#ifndef __HPLIBS_H__ +#define __HPLIBS_H__ + +#include + +#include "export.h" + +//! Enumeration of cable types. +typedef enum { + CABLE_NUL = 0, + CABLE_PRIME_HID, + CABLE_MAX +} cable_model; + +//! Enumeration of calculator types. +typedef enum { + CALC_NONE = 0, + CALC_PRIME, + CALC_MAX +} calc_model; + +//! Enumeration of logging levels. +typedef enum { + LOG_LEVEL_ALL = 0, + LOG_LEVEL_DEBUG, + LOG_LEVEL_INFO, + LOG_LEVEL_WARN, + LOG_LEVEL_ERROR +} hplibs_logging_level; + +//! Struct containing function pointers used by the libraries for dynamic memory allocation. +typedef struct { + void * (*malloc)(size_t size); ///< A malloc()-compatible function + void * (*calloc) (size_t nmemb, size_t size); ///< A calloc()-compatible function + void * (*realloc)(void *ptr, size_t size); ///< A realloc()-compatible function + void (*free) (void *ptr); ///< A free()-compatible function +} hplibs_malloc_funcs; + +//! USB Vendor ID of Hewlett-Packard. +#define USB_VID_HP (0x03F0) +//! USB Product ID of the Prime calculator in firmware revisions < 8151. +#define USB_PID_PRIME1 (0x0441) +//! USB Product ID of the Prime calculator in firmware revisions >= 8151. +#define USB_PID_PRIME2 (0x1541) + +//! Size of a raw HID packet for the Prime. +#define PRIME_RAW_HID_DATA_SIZE (64) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Gets the error message if the error was produced by a libhp* library + * \param number the error number (from above) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * + * \return the error number. + **/ +HPEXPORT int HPCALL hplibs_error_get(int number, char **message); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libhpcalcs/src/hpopers.c b/libhpcalcs/src/hpopers.c new file mode 100644 index 0000000..19d2fd2 --- /dev/null +++ b/libhpcalcs/src/hpopers.c @@ -0,0 +1,126 @@ +/* + * libhpopers: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpfiles.c Higher-level operations: base part. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include +#include + +#include +#include "internal.h" +#include "logging.h" +#include "error.h" +#include "gettext.h" + +hplibs_malloc_funcs hpopers_alloc_funcs = { + .malloc = malloc, + .calloc = calloc, + .realloc = realloc, + .free = free +}; + + +// not static, must be shared between instances +int hpopers_instance_count = 0; + +HPEXPORT int HPCALL hpopers_init(hpopers_config * config) { + int res = ERR_SUCCESS; + void (*log_callback)(const char *format, va_list args); + hplibs_malloc_funcs * alloc_funcs; + + if (config == NULL) { + log_callback = NULL; + alloc_funcs = NULL; + } + else { + if (config->version <= HPOPERS_CONFIG_VERSION) { + if (config->version == 1) { + log_callback = config->log_callback; + alloc_funcs = config->alloc_funcs; + } + else { + hpcables_error(_("%s: unsupported config version %u"), __FUNCTION__, config->version); + res = ERR_LIBRARY_CONFIG_VERSION; + } + } + else { + hpcables_error(_("%s: unsupported config version %u"), __FUNCTION__, config->version); + res = ERR_LIBRARY_CONFIG_VERSION; + } + } + + if (!res) { + // TODO: when (if) libhpopers is split from libhpcalcs, copy and adjust locale setting code from hpfiles.c. + + if (!hpopers_instance_count) { + hpopers_log_set_callback(log_callback); + if (alloc_funcs != NULL) { + hpopers_alloc_funcs = *alloc_funcs; + } + hpopers_info(_("hpopers library version %s"), hpopers_version_get()); + + hpopers_info(_("%s: init succeeded"), __FUNCTION__); + hpopers_instance_count++; + } + else { + hpopers_info(_("%s: re-init skipped"), __FUNCTION__); + hpopers_instance_count++; + } + } + + return res; +} + +HPEXPORT int HPCALL hpopers_exit(void) { + int res; + + if (hpopers_instance_count <= 0) { + hpopers_error(_("%s: more exits than inits"), __FUNCTION__); + res = ERR_LIBRARY_EXIT; + } + else { + hpopers_instance_count--; + + hpopers_info(_("%s: exit succeeded"), __FUNCTION__); + res = ERR_SUCCESS; + } + + return res; +} + + +HPEXPORT const char* HPCALL hpopers_version_get (void) { + return VERSION; +} + diff --git a/libhpcalcs/src/hpopers.h b/libhpcalcs/src/hpopers.h new file mode 100644 index 0000000..f82e717 --- /dev/null +++ b/libhpcalcs/src/hpopers.h @@ -0,0 +1,180 @@ +/* + * libhpopers: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file hpopers.h Higher-level operations: base part. + */ + +#ifndef __HPLIBS_OPERS_H__ +#define __HPLIBS_OPERS_H__ + +#include +#include +#include + +#include "hplibs.h" +#include "hpfiles.h" +#include "hpcables.h" +#include "hpcalcs.h" + + +//! Structure passed to \a hpopers_init, contains e.g. callbacks for logging and memory allocation. +typedef struct { + unsigned int version; ///< Config version number. + void (*log_callback)(const char *format, va_list args); ///< Callback function for receiving logging output. + hplibs_malloc_funcs * alloc_funcs; ///< Function pointers used for dynamic memory allocation. If NULL, the library defaults to malloc(), calloc(), realloc(), free(). +} hpopers_config; + +//! Latest revision of the \a hpopers_config struct layout supported by this version of the library. +#define HPOPERS_CONFIG_VERSION (1) + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initializes library internals. Must be called before any other libhpopers function. + * \param config pointer to struct containing e.g. callbacks passed to the library. + * \return Whether the initialization succeeded. + * \note the contents of alloc_funcs are copied. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpopers_init(hpopers_config * config); +/** + * \brief Tears down library internals. No other libhpopers function can be called after this one. + * \return Whether the teardown succeeded. + * \todo return instance count instead. + **/ +HPEXPORT int HPCALL hpopers_exit(void); + +/** + * \brief Returns the library version string. + * \return The library version string, usually under the form "X.Y.Z". + **/ +HPEXPORT const char* HPCALL hpopers_version_get(void); + +/** + * \brief Gets the error message if the error was produced by this library + * \param number the error number (from internal error.h) + * \param message out pointer for a newly allocated text error message, which must be freed by the caller + * \note the string is allocated with malloc(), therefore it must be freed with free(). + * \return 0 if the error was produced by this library, otherwise the error number (for propagation). + **/ +HPEXPORT int HPCALL hpopers_error_get(int number, char **message); + +/** + * \brief Sets the callback function used by the library for logging + * \param log_callback function pointer + */ +HPEXPORT void HPCALL hpopers_log_set_callback(void (*log_callback)(const char *format, va_list args)); +/** + * \brief Sets the log level of the library, for controlling how much logging output is produced. + * \param log_level log level (from hplibs.h) + * \return the previous log level + */ +HPEXPORT hplibs_logging_level HPCALL hpopers_log_set_level(hplibs_logging_level log_level); + + +// Tentative APIs, may change in the near future. + +/** + * \brief Retrieves a screenshot from the calculator, without any form of conversion + * \param handle the calculator handle. + * \param format the desired screenshot format. + * \param out_file struct FILE pointer for storing the output. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_recv_screen . + */ +HPEXPORT int HPCALL hpopers_oper_recv_screen_verbatim_to_file(calc_handle * handle, calc_screenshot_format format, FILE * out_file); +/** + * \brief Retrieves a screenshot from the calculator, and convert it to R8G8B8 before recompressing it as PNG. + * \param handle the calculator handle. + * \param format the desired screenshot format. + * \param out_data storage area for converted R8G8B8 screenshot. + * \param out_size storage area for size of the R8G8B8 screenshot contained in the calculator's reply. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_recv_screen and \a hpopers_oper_convert_raw_screen_to_png_r8g8b8. + */ +HPEXPORT int HPCALL hpopers_oper_recv_screen_png_r8g8b8(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); +/** + * \brief Retrieves a screenshot from the calculator, and convert it to R8G8B8 before recompressing it as PNG and writing it to a file. + * \param handle the calculator handle. + * \param format the desired screenshot format. + * \param out_file struct FILE pointer for storing the output. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpopers_oper_recv_screen_png_r8g8b8 . + */ +HPEXPORT int HPCALL hpopers_oper_recv_screen_png_r8g8b8_to_file(calc_handle * handle, calc_screenshot_format format, FILE * out_file); +/** + * \brief Converts a raw screenshot (output by e.g. \a hpcalcs_calc_recv_screen) to a more usual PNG R8G8B8 format. + * \param in_data storage area for raw screenshot. + * \param in_size storage area for size of the raw screenshot. + * \param format the desired screenshot format. + * \param out_data storage area for R8G8B8 screenshot. + * \param out_size storage area for size of the R8G8B8 screenshot. + * \return 0 upon success, nonzero otherwise. + */ +HPEXPORT int HPCALL hpopers_oper_convert_raw_screen_to_png_r8g8b8(uint8_t * in_data, uint32_t in_size, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); +/** + * \brief Sends a file to the calculator. + * \param handle the calculator handle. + * \param file struct FILE pointer containing the contents to be sent. + * \param filename struct FILE pointer containing the contents to be sent. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_send_file . + */ +HPEXPORT int HPCALL hpopers_calc_send_file(calc_handle * handle, FILE * file, const char16_t * filename); +/** + * \brief Receives a file from the calculator. + * \param handle the calculator handle. + * \param calculator_filename name (on the calculator side) of the file to be received. + * \param file struct FILE pointer used for writing data. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_recv_file . + */ +HPEXPORT int HPCALL hpopers_calc_recv_file(calc_handle * handle, const char16_t * calculator_filename, FILE * file); +/** + * \brief Receives a backup (made of multiple files) from the calculator to a folder. + * \param handle the calculator handle. + * \param out_path name of the folder used as root for the files hierarchy. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_recv_backup . + */ +HPEXPORT int HPCALL hpopers_calc_recv_backup(calc_handle * handle, const char * out_path); +/** + * \brief Sends a backup (made of multiple files) from a folder to the calculator. + * \param handle the calculator handle. + * \param in_path name of the folder used as root for the files hierarchy. + * \return 0 upon success, nonzero otherwise. + * \note This shall be a wrapper over \a hpcalcs_calc_send_file (called in a loop) . + */ +HPEXPORT int HPCALL hpopers_calc_send_backup(calc_handle * handle, const char * in_path); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libhpcalcs/src/internal.h b/libhpcalcs/src/internal.h new file mode 100644 index 0000000..c64fa2f --- /dev/null +++ b/libhpcalcs/src/internal.h @@ -0,0 +1,32 @@ +/* + * libhpfiles, libhpcables, libhpcalcs, libhpopers: hand-helds support libraries. + * Copyright (C) 2015 Lionel Debroux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file internal.h Files, Cables, Calcs, Opers: internal definitions for libhpfiles, libhpcables, libhpcalcs, libhpopers. + */ + +#ifndef __HPLIBS_INTERNAL_H__ +#define __HPLIBS_INTERNAL_H__ + +extern hplibs_malloc_funcs hpfiles_alloc_funcs; +extern hplibs_malloc_funcs hpcables_alloc_funcs; +extern hplibs_malloc_funcs hpcalcs_alloc_funcs; +extern hplibs_malloc_funcs hpopers_alloc_funcs; + +#endif diff --git a/libhpcalcs/src/link_nul.c b/libhpcalcs/src/link_nul.c new file mode 100644 index 0000000..7acf330 --- /dev/null +++ b/libhpcalcs/src/link_nul.c @@ -0,0 +1,78 @@ +/* + * libhpcables: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file link_nul.c Cables: Null cable. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +static int cable_nul_probe(cable_handle * handle) { + return 0; +} + +static int cable_nul_open(cable_handle * handle) { + handle->model = CABLE_NUL; + handle->handle = NULL; + handle->fncts = NULL; + handle->read_timeout = 0; + handle->open = 0; + handle->busy = 0; + return 0; +} + +static int cable_nul_close(cable_handle * handle) { + return 0; +} + + +static int cable_nul_set_read_timeout(cable_handle * handle, int read_timeout) { + return 0; +} + + +static int cable_nul_send(cable_handle * handle, uint8_t * data, uint32_t len) { + return 0; +} + +static int cable_nul_recv(cable_handle * handle, uint8_t ** data, uint32_t * len) { + return 0; +} + +const cable_fncts cable_nul_fncts = +{ + CABLE_NUL, + "Dummy cable", + "Dummy cable used when no cable is set", + &cable_nul_probe, + &cable_nul_open, + &cable_nul_close, + &cable_nul_set_read_timeout, + &cable_nul_send, + &cable_nul_recv +}; diff --git a/libhpcalcs/src/link_prime_hid.c b/libhpcalcs/src/link_prime_hid.c new file mode 100644 index 0000000..6815def --- /dev/null +++ b/libhpcalcs/src/link_prime_hid.c @@ -0,0 +1,240 @@ +/* + * libhpcables: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file link_prime_hid.c Cables: Prime HID cable. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + +#include +#include +#include "logging.h" +#include "error.h" + +extern const cable_fncts cable_prime_hid_fncts; + +static int cable_prime_hid_probe(cable_handle * handle) { + int res; + // In fact, we're not using handle here, but let's nevertheless flag misuse of the API. + if (handle != NULL) { + // Enumerating the device seems to do the job. + struct hid_device_info * info = hid_enumerate(USB_VID_HP, USB_PID_PRIME1); + if (info != NULL) { + hid_free_enumeration(info); + res = ERR_SUCCESS; + hpcables_info("%s: cable probe succeeded, PID=%04X", __FUNCTION__, USB_PID_PRIME1); + } + else { + info = hid_enumerate(USB_VID_HP, USB_PID_PRIME2); + if (info != NULL) { + hid_free_enumeration(info); + res = ERR_SUCCESS; + hpcables_info("%s: cable probe succeeded, PID=%04X", __FUNCTION__, USB_PID_PRIME2); + } + else { + res = ERR_CABLE_PROBE_FAILED; + hpcables_error("%s: cable probe failed", __FUNCTION__); + } + } + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +static int cable_prime_hid_open(cable_handle * handle) { + int res; + if (handle != NULL) { + hid_device * device_handle = hid_open(USB_VID_HP, USB_PID_PRIME1, NULL); + unsigned int pid = USB_PID_PRIME1; + if (device_handle) { +device_handle_ok: + handle->model = CABLE_PRIME_HID; + handle->handle = (void *)device_handle; + handle->fncts = &cable_prime_hid_fncts; + // Especially screenshots can take a while before beginning to send data. + handle->read_timeout = 8000; + handle->open = 1; + handle->busy = 0; + res = ERR_SUCCESS; + hpcables_info("%s: cable open succeeded, PID=%04X", __FUNCTION__, pid); + } + else { + device_handle = hid_open(USB_VID_HP, USB_PID_PRIME2, NULL); + pid = USB_PID_PRIME2; + if (device_handle) { + goto device_handle_ok; + } + else { + res = ERR_CABLE_NOT_OPEN; + hpcables_error("%s: cable open failed", __FUNCTION__); + } + } + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +static int cable_prime_hid_close(cable_handle * handle) { + int res; + if (handle != NULL) { + hid_device * device_handle = (hid_device *)handle->handle; + if (device_handle != NULL) { + if (handle->open) { + hid_close(device_handle); + handle->model = CABLE_NUL; + handle->handle = NULL; + handle->fncts = NULL; + handle->open = 0; + res = ERR_SUCCESS; + hpcables_info("%s: cable close succeeded", __FUNCTION__); + } + else { + res = ERR_CABLE_NOT_OPEN; + hpcables_error("%s: cable was not open", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: device_handle is NULL", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +static int cable_prime_hid_set_read_timeout(cable_handle * handle, int read_timeout) { + int res; + if (handle != NULL) { + res = ERR_SUCCESS; + handle->read_timeout = read_timeout; + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + + +static int cable_prime_hid_send(cable_handle * handle, uint8_t * data, uint32_t len) { + int res; + if (handle != NULL && data != NULL) { + hid_device * device_handle = (hid_device *)handle->handle; + if (device_handle != NULL) { + uint32_t bytes_written = 0; + while (bytes_written < len) { + if (handle->open) { + res = hid_write(device_handle, data + bytes_written, len - bytes_written); + if (res >= 0) { + bytes_written += res; + } + else { + res = ERR_CABLE_WRITE_ERROR; + hpcables_error("%s: write failed %ls", __FUNCTION__, hid_error(device_handle)); + return res; + } + } + else { + res = ERR_CABLE_NOT_OPEN; + hpcables_error("%s: cable was not open", __FUNCTION__); + return res; + } + } + res = ERR_SUCCESS; + hpcables_info("%s: wrote %d bytes", __FUNCTION__, bytes_written); + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: device_handle is NULL", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcables_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} + +static int cable_prime_hid_recv(cable_handle * handle, uint8_t ** data, uint32_t * len) { + int res; + // Use pre-allocated area pointed to by data. + if (handle != NULL && data != NULL && *data != NULL && len != NULL) { + hid_device * device_handle = (hid_device *)handle->handle; + if (device_handle != NULL) { + if (handle->open) { + res = hid_read_timeout(device_handle, *data, PRIME_RAW_HID_DATA_SIZE, handle->read_timeout); + if (res >= 0) { + *len = res; + res = ERR_SUCCESS; + hpcables_info("%s: read %" PRIu32 "bytes", __FUNCTION__, *len); + } + else { + res = ERR_CABLE_READ_ERROR; + hpcables_error("%s: read failed", __FUNCTION__); + } + } + else { + res = ERR_CABLE_NOT_OPEN; + hpcables_error("%s: cable was not open", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcables_error("%s: device_handle is NULL", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcables_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} + +const cable_fncts cable_prime_hid_fncts = +{ + CABLE_PRIME_HID, + "Prime HID cable", + "Prime HID cable", + &cable_prime_hid_probe, + &cable_prime_hid_open, + &cable_prime_hid_close, + &cable_prime_hid_set_read_timeout, + &cable_prime_hid_send, + &cable_prime_hid_recv +}; diff --git a/libhpcalcs/src/logging.c b/libhpcalcs/src/logging.c new file mode 100644 index 0000000..5d49261 --- /dev/null +++ b/libhpcalcs/src/logging.c @@ -0,0 +1,179 @@ +/* + * libhpfiles, libhpcables, libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file logging.c Logging primitives + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "logging.h" + +#include +#include +#include + +#ifdef __GNUC__ +#ifndef alloca +#define alloca(size) __builtin_alloca(size) +#endif +#endif + +void (*hpfiles_log_callback)(const char *format, va_list args); +hplibs_logging_level hpfiles_log_level = LOG_LEVEL_ALL; + +void (*hpcables_log_callback)(const char *format, va_list args); +hplibs_logging_level hpcables_log_level = LOG_LEVEL_ALL; + +void (*hpcalcs_log_callback)(const char *format, va_list args); +hplibs_logging_level hpcalcs_log_level = LOG_LEVEL_ALL; + +void (*hpopers_log_callback)(const char *format, va_list args); +hplibs_logging_level hpopers_log_level = LOG_LEVEL_ALL; + + +#define DEBUG_FUNC_BODY(lib, level) \ + if (lib##_log_callback != NULL && lib##_log_level <= LOG_LEVEL_##level) { \ + va_list args; \ + char * format2; \ + va_start (args, format); \ + format2 = (char *)alloca(strlen(format) + sizeof(#lib " " #level ": ") + 10); \ + sprintf(format2, #lib " " #level ": %s\n", format); \ + (*lib##_log_callback)(format2, args); \ + } + +HPEXPORT void HPCALL hpfiles_log_set_callback(void (*log_callback)(const char *format, va_list args)) { + hpfiles_log_callback = log_callback; +} + +HPEXPORT hplibs_logging_level HPCALL hpfiles_log_set_level(hplibs_logging_level log_level) { + hplibs_logging_level ret = hpfiles_log_level; + hpfiles_log_level = log_level; + return ret; +} + +void hpfiles_debug (const char *format, ...) { + DEBUG_FUNC_BODY(hpfiles, DEBUG) +} + +void hpfiles_info (const char *format, ...) { + DEBUG_FUNC_BODY(hpfiles, INFO) +} + +void hpfiles_warning (const char *format, ...) { + DEBUG_FUNC_BODY(hpfiles, WARN) +} + +void hpfiles_error (const char *format, ...) { + DEBUG_FUNC_BODY(hpfiles, ERROR) +} + + + +HPEXPORT void HPCALL hpcables_log_set_callback(void (*log_callback)(const char *format, va_list args)) { + hpcables_log_callback = log_callback; +} + +HPEXPORT hplibs_logging_level HPCALL hpcables_log_set_level(hplibs_logging_level log_level) { + hplibs_logging_level ret = hpcables_log_level; + hpcables_log_level = log_level; + return ret; +} + +void hpcables_debug (const char *format, ...) { + DEBUG_FUNC_BODY(hpcables, DEBUG) +} + +void hpcables_info (const char *format, ...) { + DEBUG_FUNC_BODY(hpcables, INFO) +} + +void hpcables_warning (const char *format, ...) { + DEBUG_FUNC_BODY(hpcables, WARN) +} + +void hpcables_error (const char *format, ...) { + DEBUG_FUNC_BODY(hpcables, ERROR) +} + + + +HPEXPORT void HPCALL hpcalcs_log_set_callback(void (*log_callback)(const char *format, va_list args)) { + hpcalcs_log_callback = log_callback; +} + +HPEXPORT hplibs_logging_level HPCALL hpcalcs_log_set_level(hplibs_logging_level log_level) { + hplibs_logging_level ret = hpcalcs_log_level; + hpcalcs_log_level = log_level; + return ret; +} + +void hpcalcs_debug (const char *format, ...) { + DEBUG_FUNC_BODY(hpcalcs, DEBUG) +} + +void hpcalcs_info (const char *format, ...) { + DEBUG_FUNC_BODY(hpcalcs, INFO) +} + +void hpcalcs_warning (const char *format, ...) { + DEBUG_FUNC_BODY(hpcalcs, WARN) +} + +void hpcalcs_error (const char *format, ...) { + DEBUG_FUNC_BODY(hpcalcs, ERROR) +} + + + +HPEXPORT void HPCALL hpopers_log_set_callback(void (*log_callback)(const char *format, va_list args)) { + hpopers_log_callback = log_callback; +} + +HPEXPORT hplibs_logging_level HPCALL hpopers_log_set_level(hplibs_logging_level log_level) { + hplibs_logging_level ret = hpopers_log_level; + hpopers_log_level = log_level; + return ret; +} + +void hpopers_debug (const char *format, ...) { + DEBUG_FUNC_BODY(hpopers, DEBUG) +} + +void hpopers_info (const char *format, ...) { + DEBUG_FUNC_BODY(hpopers, INFO) +} + +void hpopers_warning (const char *format, ...) { + DEBUG_FUNC_BODY(hpopers, WARN) +} + +void hpopers_error (const char *format, ...) { + DEBUG_FUNC_BODY(hpopers, ERROR) +} diff --git a/libhpcalcs/src/logging.h b/libhpcalcs/src/logging.h new file mode 100644 index 0000000..f7ba2c5 --- /dev/null +++ b/libhpcalcs/src/logging.h @@ -0,0 +1,56 @@ +/* + * libhpfiles, libhpcables, libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file logging.h Logging primitives. + */ + +#ifndef __HPLIBS_LOGGING_H__ +#define __HPLIBS_LOGGING_H__ + +#include + +void hpfiles_debug (const char *format, ...); +void hpfiles_info (const char *format, ...); +void hpfiles_warning (const char *format, ...); +void hpfiles_error (const char *format, ...); + + +void hpcables_debug (const char *format, ...); +void hpcables_info (const char *format, ...); +void hpcables_warning (const char *format, ...); +void hpcables_error (const char *format, ...); + + +void hpcalcs_debug (const char *format, ...); +void hpcalcs_info (const char *format, ...); +void hpcalcs_warning (const char *format, ...); +void hpcalcs_error (const char *format, ...); + + +void hpopers_debug (const char *format, ...); +void hpopers_info (const char *format, ...); +void hpopers_warning (const char *format, ...); +void hpopers_error (const char *format, ...); + +#endif diff --git a/libhpcalcs/src/prime_cmd.c b/libhpcalcs/src/prime_cmd.c new file mode 100644 index 0000000..2d61aa2 --- /dev/null +++ b/libhpcalcs/src/prime_cmd.c @@ -0,0 +1,787 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file prime_cmd.c Calcs: Prime commands + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "prime_cmd.h" +#include "logging.h" +#include "error.h" +#include "utils.h" + +#include +#include +#include +#include + +static inline uint16_t crc16_block(const uint8_t * buffer, uint32_t len) { + static const uint16_t ccitt_crc16_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 + }; + uint16_t crc = 0; + + while (len--) { + crc = ccitt_crc16_table[(crc >> 8) ^ *buffer++] ^ (crc << 8); + } + return crc; +} + +static int read_vtl_pkt(calc_handle * handle, uint8_t cmd, prime_vtl_pkt ** pkt, int packet_contains_header) { + int res; + (void)packet_contains_header; + *pkt = prime_vtl_pkt_new(0); + if (*pkt != NULL) { + (*pkt)->cmd = cmd; + res = prime_recv_data(handle, *pkt); + if (res == ERR_SUCCESS) { + if ((*pkt)->size > 0) { + if ((*pkt)->data[0] == (*pkt)->cmd) { + hpcalcs_debug("%s: command matches returned data", __FUNCTION__); + } + else { + hpcalcs_debug("%s: command does not match returned data", __FUNCTION__); + // It's not necessarily an error. + } + } + else { + hpcalcs_info("%s: empty packet", __FUNCTION__); + } + } + else { + prime_vtl_pkt_del(*pkt); + *pkt = NULL; + } + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + return res; +} + +static int write_vtl_pkt(calc_handle * handle, prime_vtl_pkt * pkt) { + return prime_send_data(handle, pkt); +} + +HPEXPORT int HPCALL calc_prime_s_check_ready(calc_handle * handle) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt = prime_vtl_pkt_new(1); + if (pkt != NULL) { + uint8_t * ptr; + + pkt->cmd = CMD_PRIME_CHECK_READY; + ptr = pkt->data; + *ptr++ = CMD_PRIME_CHECK_READY; + res = write_vtl_pkt(handle, pkt); + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_check_ready(calc_handle * handle, uint8_t ** out_data, uint32_t * out_size) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt; + res = read_vtl_pkt(handle, CMD_PRIME_CHECK_READY, &pkt, 0); + if (res == ERR_SUCCESS && pkt != NULL) { + if (out_data != NULL && out_size != NULL) { + *out_size = pkt->size; + *out_data = pkt->data; // Transfer ownership of the memory block to the caller. + pkt->data = NULL; // Detach it from virtual packet. + } + // else do nothing. res is already ERR_SUCCESS. + prime_vtl_pkt_del(pkt); + } + else { + hpcalcs_error("%s: failed to read packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_s_get_infos (calc_handle * handle) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt = prime_vtl_pkt_new(1); + if (pkt != NULL) { + uint8_t * ptr; + + pkt->cmd = CMD_PRIME_GET_INFOS; + ptr = pkt->data; + *ptr++ = CMD_PRIME_GET_INFOS; + res = write_vtl_pkt(handle, pkt); + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_get_infos (calc_handle * handle, calc_infos * infos) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt; + res = read_vtl_pkt(handle, CMD_PRIME_GET_INFOS, &pkt, 1); + if (res == ERR_SUCCESS && pkt != NULL) { + if (infos != NULL) { + infos->size = pkt->size; + infos->data = pkt->data; // Transfer ownership of the memory block to the caller. + pkt->data = NULL; // Detach it from virtual packet. + } + // else do nothing. res is already ERR_SUCCESS. + prime_vtl_pkt_del(pkt); + } + else { + hpcalcs_error("%s: failed to read packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_s_set_date_time(calc_handle * handle, time_t timestamp) { + int res; + if (handle != NULL) { + struct tm * brokendowntime = localtime(×tamp); + if (brokendowntime != NULL) { + uint32_t size = 10; // Size of the data after the header. + prime_vtl_pkt * pkt = prime_vtl_pkt_new(size + 6); // Add size of the header. + if (pkt != NULL) { + uint8_t * ptr; + + pkt->cmd = CMD_PRIME_SET_DATE_TIME; + ptr = pkt->data; + *ptr++ = CMD_PRIME_SET_DATE_TIME; + *ptr++ = 0x01; + *ptr++ = (uint8_t)((size >> 24) & 0xFF); + *ptr++ = (uint8_t)((size >> 16) & 0xFF); + *ptr++ = (uint8_t)((size >> 8) & 0xFF); + *ptr++ = (uint8_t)((size ) & 0xFF); + *ptr++ = 0x00; // ? + *ptr++ = 0x00; // ? + *ptr++ = 0x54; // 84 decimal, ? + *ptr++ = 0x1E; // 30 decimal, ? + *ptr++ = brokendowntime->tm_year - (2000 - 1900); // tm_year: The number of years since 1900. + *ptr++ = brokendowntime->tm_mon + 1; // tm_mon: the number of months since January, in the range 0 to 11. + *ptr++ = brokendowntime->tm_mday; + *ptr++ = brokendowntime->tm_hour; + *ptr++ = brokendowntime->tm_min; + *ptr++ = brokendowntime->tm_sec; + res = write_vtl_pkt(handle, pkt); + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_CALC_SPLIT_TIMESTAMP; + hpcalcs_error("%s: couldn't split timestamp", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_set_date_time(calc_handle * handle) { + int res = 0; + if (handle != NULL) { + // There doesn't seem to be anything to do. + //res = calc_prime_r_check_ready(handle, NULL, NULL); + } + else { + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_s_recv_screen(calc_handle * handle, calc_screenshot_format format) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt = prime_vtl_pkt_new(2); + if (pkt != NULL) { + uint8_t * ptr; + + pkt->cmd = CMD_PRIME_RECV_SCREEN; + ptr = pkt->data; + *ptr++ = CMD_PRIME_RECV_SCREEN; + *ptr++ = (uint8_t)format; + res = write_vtl_pkt(handle, pkt); + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_recv_screen(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt; + res = read_vtl_pkt(handle, CMD_PRIME_RECV_SCREEN, &pkt, 1); + if (res == ERR_SUCCESS && pkt != NULL) { + if (pkt->size > 13) { + // Packet has CRC + uint16_t computed_crc; // 0x0000 ? + uint8_t * ptr = pkt->data; + // For whatever reason the CRC seems to be encoded the other way around compared to receiving files + uint16_t embedded_crc = (((uint16_t)(ptr[6])) << 8) | ((uint16_t)(ptr[7])); + // Reset CRC before computing + ptr[6] = 0x00; + ptr[7] = 0x00; + computed_crc = crc16_block(ptr + 6, pkt->size - 6); // The CRC for *screenshots* skips the header, and includes all data. + hpcalcs_info("%s: embedded=%" PRIX16 " computed=%" PRIX16, __FUNCTION__, embedded_crc, computed_crc); + if (computed_crc != embedded_crc) { + res = ERR_CALC_PACKET_FORMAT; + hpcalcs_error("%s: CRC mismatch", __FUNCTION__); + } + + // Skip marker. + if (pkt->data[8] == (uint8_t)format && pkt->data[9] == 0xFF && pkt->data[10] == 0xFF && pkt->data[11] == 0xFF && pkt->data[12] == 0xFF) { + if (out_data != NULL && out_size != NULL) { + *out_size = pkt->size - 13; + memmove(pkt->data, pkt->data + 13, pkt->size - 13); + *out_data = pkt->data; // Transfer ownership of the memory block to the caller. + pkt->data = NULL; // Detach it from virtual packet. + } + // else do nothing. res is already ERR_SUCCESS. + } + else { + res = ERR_CALC_PACKET_FORMAT; + hpcalcs_warning("%s: unknown marker at beginning of image", __FUNCTION__); + } + } + else { + res = ERR_CALC_PACKET_FORMAT; + hpcalcs_info("%s: packet is too short: %" PRIu32 "bytes", __FUNCTION__, pkt->size); + } + prime_vtl_pkt_del(pkt); + } + else { + hpcalcs_error("%s: failed to read packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +// Seems to be made of a series of CMD_PRIME_RECV_FILE. +HPEXPORT int HPCALL calc_prime_s_send_file(calc_handle * handle, files_var_entry * file) { + int res; + if (handle != NULL && file != NULL) { + uint8_t namelen = (uint8_t)char16_strlen(file->name) * 2; + uint32_t size = 10 - 6 + namelen + file->size; // Size of the data after the header. + prime_vtl_pkt * pkt = prime_vtl_pkt_new(size + 6); // Add size of the header. + hpcalcs_debug("Virtual packet has size %" PRIu32 " (%" PRIx32 ")\n", size, size); + if (pkt != NULL) { + uint8_t * ptr; + uint16_t crc16; + uint32_t offset = 0; + + // Some text editors add the UTF-16LE BOM at the beginning of the file, but the SDKV0.30 firmware version chokes on it. + // Therefore, skip the BOM. + if ( (file->type == PRIME_TYPE_PRGM || file->type == PRIME_TYPE_NOTE) + && (file->data[0] == 0xFF && file->data[1] == 0xFE) + ) { + offset = 2; + size -= 2; + } + + pkt->cmd = CMD_PRIME_RECV_FILE; + ptr = pkt->data; + *ptr++ = CMD_PRIME_RECV_FILE; + *ptr++ = 0x01; + *ptr++ = (uint8_t)((size >> 24) & 0xFF); + *ptr++ = (uint8_t)((size >> 16) & 0xFF); + *ptr++ = (uint8_t)((size >> 8) & 0xFF); + *ptr++ = (uint8_t)((size ) & 0xFF); + *ptr++ = file->type; + *ptr++ = namelen; + *ptr++ = 0x00; // CRC16, set it to 0 for now. + *ptr++ = 0x00; + memcpy(ptr, file->name, namelen); + ptr += namelen; + memcpy(ptr, file->data + offset, file->size - offset); + crc16 = crc16_block(pkt->data, size); // Yup, the last 6 bytes of the packet are excluded from the CRC. + pkt->data[8] = crc16 & 0xFF; + pkt->data[9] = (crc16 >> 8) & 0xFF; + res = write_vtl_pkt(handle, pkt); + + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_send_file(calc_handle * handle) { + int res; + if (handle != NULL) { + // There doesn't seem to be anything to do, beyond eliminating packets starting with 0xFF. + res = calc_prime_r_check_ready(handle, NULL, NULL); + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +// Receiving an individual file from the calculator seems to start by a CMD_PRIME_REQ_FILE. +HPEXPORT int HPCALL calc_prime_s_recv_file(calc_handle * handle, files_var_entry * file) { + int res; + if (handle != NULL && file != NULL) { + uint8_t namelen = (uint8_t)char16_strlen(file->name) * 2; + uint32_t size = 10 - 6 + namelen; // Size of the data after the header. + prime_vtl_pkt * pkt = prime_vtl_pkt_new(size + 6); // Add size of the header. + if (pkt != NULL) { + uint8_t * ptr; + uint16_t crc16; + + pkt->cmd = CMD_PRIME_RECV_FILE; + ptr = pkt->data; + *ptr++ = CMD_PRIME_REQ_FILE; + *ptr++ = 0x01; + *ptr++ = (uint8_t)((size >> 24) & 0xFF); + *ptr++ = (uint8_t)((size >> 16) & 0xFF); + *ptr++ = (uint8_t)((size >> 8) & 0xFF); + *ptr++ = (uint8_t)((size ) & 0xFF); + *ptr++ = file->type; + *ptr++ = namelen; + *ptr++ = 0x00; // CRC16, set it to 0 for now. + *ptr++ = 0x00; + memcpy(ptr, file->name, namelen); + crc16 = crc16_block(pkt->data, size); // Yup, the last 6 bytes are excluded from the CRC. + pkt->data[8] = crc16 & 0xFF; + pkt->data[9] = (crc16 >> 8) & 0xFF; + res = write_vtl_pkt(handle, pkt); + + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_recv_file(calc_handle * handle, files_var_entry ** out_file) { + int res; + prime_vtl_pkt * pkt; + // TODO: if no file was received, have *out_file = NULL, but res = 0. + if (handle != NULL) { + res = read_vtl_pkt(handle, CMD_PRIME_RECV_FILE, &pkt, 1); + if (res == ERR_SUCCESS && pkt != NULL) { + if (pkt->size >= 11) { + // Packet has CRC + uint16_t computed_crc; // 0x0000 ? + uint8_t * ptr = pkt->data; + uint16_t embedded_crc = (((uint16_t)(ptr[9])) << 8) | ((uint16_t)(ptr[8])); + // Reset CRC before computing + ptr[8] = 0x00; + ptr[9] = 0x00; + computed_crc = crc16_block(ptr, pkt->size - 6); // The CRC contains the initial 0x00, but not the final 6 bytes (...). + hpcalcs_info("%s: embedded=%" PRIX16 " computed=%" PRIX16, __FUNCTION__, embedded_crc, computed_crc); + if (computed_crc != embedded_crc) { + hpcalcs_error("%s: CRC mismatch", __FUNCTION__); + } + + if (out_file != NULL) { + uint8_t namelen; + uint32_t size; + uint8_t filetype; + + *out_file = NULL; + filetype = pkt->data[6]; + namelen = pkt->data[7]; + size = pkt->size - 10 - namelen; + + if (!(size & UINT32_C(0x80000000))) { + *out_file = hpfiles_ve_create_with_data(&pkt->data[10 + namelen], size); + if (*out_file != NULL) { + (*out_file)->type = filetype; + memcpy((*out_file)->name, &pkt->data[10], namelen); + (*out_file)->invalid = (computed_crc != embedded_crc); + hpcalcs_info("%s: created entry for %ls with size %" PRIu32 " and type %02X", __FUNCTION__, (*out_file)->name, (*out_file)->size, filetype); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create entry", __FUNCTION__); + } + } + else { + res = ERR_CALC_PACKET_FORMAT; + hpcalcs_error("%s: weird size (packet too short ?)", __FUNCTION__); + // TODO: change res. + } + } + } + else { + if (pkt->data[0] != 0xF9) { + res = ERR_CALC_PACKET_FORMAT; + hpcalcs_info("%s: packet is too short: %" PRIu32 "bytes", __FUNCTION__, pkt->size); + } + else { + hpcalcs_info("%s: skipping F9 packet", __FUNCTION__); + } + if (out_file != NULL) { + *out_file = NULL; + } + } + prime_vtl_pkt_del(pkt); + } + else { + hpcalcs_error("%s: failed to read packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_s_recv_backup(calc_handle * handle) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt = prime_vtl_pkt_new(1); + if (pkt != NULL) { + uint8_t * ptr; + + pkt->cmd = CMD_PRIME_RECV_FILE; + ptr = pkt->data; + *ptr++ = CMD_PRIME_RECV_BACKUP; + res = write_vtl_pkt(handle, pkt); + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_recv_backup(calc_handle * handle, files_var_entry *** out_vars) { + int res; + if (handle != NULL) { + // TODO: in order to be more robust against packet losses, + // rewrite this code to read as much as possible, then attempt to split data according to file headers. + uint32_t count = 0; + files_var_entry ** entries = hpfiles_ve_create_array(count); + if (entries != NULL) { + for (;;) { + if (out_vars != NULL) { + *out_vars = entries; + } + res = calc_prime_r_recv_file(handle, &entries[count]); + if (res == ERR_SUCCESS) { + if (entries[count] != NULL) { + files_var_entry ** new_entries; + hpcalcs_info("%s: continuing due to non-empty entry", __FUNCTION__); + count++; + new_entries = hpfiles_ve_resize_array(entries, count); + if (new_entries != NULL) { + entries = new_entries; + entries[count] = NULL; + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't resize entries", __FUNCTION__); + break; + } + } + else { + hpcalcs_info("%s: breaking due to empty file", __FUNCTION__); + res = ERR_SUCCESS; + break; + } + } + else { + hpcalcs_error("%s: breaking due to reception failure", __FUNCTION__); + break; + } + } + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create entries", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_s_send_key(calc_handle * handle, uint32_t code) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt = prime_vtl_pkt_new(7); + if (pkt != NULL) { + uint8_t * ptr; + + pkt->cmd = CMD_PRIME_SEND_KEY; + ptr = pkt->data; + *ptr++ = CMD_PRIME_SEND_KEY; + *ptr++ = 0x01; + *ptr++ = 0x00; + *ptr++ = 0x00; + *ptr++ = 0x00; + *ptr++ = 0x01; + *ptr++ = (uint8_t)code; + res = write_vtl_pkt(handle, pkt); + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_send_key(calc_handle * handle) { + int res = 0; + if (handle != NULL) { + // There doesn't seem to be anything to do. + //res = calc_prime_r_check_ready(handle, NULL, NULL); + } + else { + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_s_send_keys(calc_handle * handle, const uint8_t * data, uint32_t size) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt = prime_vtl_pkt_new(6 + size); + if (pkt != NULL) { + uint8_t * ptr; + + pkt->cmd = CMD_PRIME_SEND_KEY; + ptr = pkt->data; + *ptr++ = CMD_PRIME_SEND_KEY; + *ptr++ = 0x01; + *ptr++ = (uint8_t)((size >> 24) & 0xFF); + *ptr++ = (uint8_t)((size >> 16) & 0xFF); + *ptr++ = (uint8_t)((size >> 8) & 0xFF); + *ptr++ = (uint8_t)((size ) & 0xFF); + memcpy(ptr, data, size); + res = write_vtl_pkt(handle, pkt); + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_send_keys(calc_handle * handle) { + int res = 0; + if (handle != NULL) { + // There doesn't seem to be anything to do. + //res = calc_prime_r_check_ready(handle, NULL, NULL); + } + else { + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_s_send_chat(calc_handle * handle, const uint16_t * data, uint32_t size) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt = prime_vtl_pkt_new(size + 6); + if (pkt != NULL) { + uint8_t * ptr; + + pkt->cmd = CMD_PRIME_SEND_CHAT; + ptr = pkt->data; + *ptr++ = CMD_PRIME_SEND_CHAT; + *ptr++ = 0x01; + *ptr++ = (uint8_t)((size >> 24) & 0xFF); + *ptr++ = (uint8_t)((size >> 16) & 0xFF); + *ptr++ = (uint8_t)((size >> 8) & 0xFF); + *ptr++ = (uint8_t)((size ) & 0xFF); + memcpy(ptr, data, size); + res = write_vtl_pkt(handle, pkt); + prime_vtl_pkt_del(pkt); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: couldn't create packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_send_chat(calc_handle * handle) { + int res = 0; + if (handle != NULL) { + // There doesn't seem to be anything to do. + //res = calc_prime_r_check_ready(handle, NULL, NULL); + } + else { + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL calc_prime_r_recv_chat(calc_handle * handle, uint16_t ** out_data, uint32_t * out_size) { + int res; + if (handle != NULL) { + prime_vtl_pkt * pkt; + res = read_vtl_pkt(handle, CMD_PRIME_RECV_CHAT, &pkt, 0); + if (res == ERR_SUCCESS && pkt != NULL) { + if (pkt->size >= 8) { + if (out_data != NULL && out_size != NULL) { + *out_size = pkt->size - 6; + memmove(pkt->data, pkt->data + 6, pkt->size - 6); + *out_data = (uint16_t *)pkt->data; // Transfer ownership of the memory block to the caller. + pkt->data = NULL; // Detach it from virtual packet. + } + } + else { + res = ERR_CALC_PACKET_FORMAT; + hpcalcs_info("%s: packet is too short: %" PRIu32 "bytes", __FUNCTION__, pkt->size); + } + prime_vtl_pkt_del(pkt); + } + else { + hpcalcs_error("%s: failed to read packet", __FUNCTION__); + } + } + else { + res = ERR_INVALID_HANDLE; + hpcalcs_error("%s: handle is NULL", __FUNCTION__); + } + return res; +} diff --git a/libhpcalcs/src/prime_cmd.h b/libhpcalcs/src/prime_cmd.h new file mode 100644 index 0000000..b8a1994 --- /dev/null +++ b/libhpcalcs/src/prime_cmd.h @@ -0,0 +1,73 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file prime_cmd.h Calcs: Prime commands + */ + +#ifndef __HPLIBS_CALCS_PRIME_CMD_H__ +#define __HPLIBS_CALCS_PRIME_CMD_H__ + +#define CMD_PRIME_CHECK_READY (0xFF) +#define CMD_PRIME_GET_INFOS (0xFA) +#define CMD_PRIME_RECV_SCREEN (0xFC) +#define CMD_PRIME_RECV_BACKUP (0xF9) +#define CMD_PRIME_REQ_FILE (0xF8) +#define CMD_PRIME_RECV_FILE (0xF7) +#define CMD_PRIME_SEND_CHAT (0xF2) +#define CMD_PRIME_RECV_CHAT (0xF2) +#define CMD_PRIME_SEND_KEY (0xEC) +#define CMD_PRIME_SET_DATE_TIME (0xE7) + +HPEXPORT int HPCALL calc_prime_s_check_ready(calc_handle * handle); +HPEXPORT int HPCALL calc_prime_r_check_ready(calc_handle * handle, uint8_t ** out_data, uint32_t * out_size); + +HPEXPORT int HPCALL calc_prime_s_get_infos(calc_handle * handle); +HPEXPORT int HPCALL calc_prime_r_get_infos(calc_handle * handle, calc_infos * infos); + +HPEXPORT int HPCALL calc_prime_s_set_date_time(calc_handle * handle, time_t timestamp); +HPEXPORT int HPCALL calc_prime_r_set_date_time(calc_handle * handle); + +HPEXPORT int HPCALL calc_prime_s_recv_screen(calc_handle * handle, calc_screenshot_format format); +HPEXPORT int HPCALL calc_prime_r_recv_screen(calc_handle * handle, calc_screenshot_format format, uint8_t ** out_data, uint32_t * out_size); + +HPEXPORT int HPCALL calc_prime_s_send_file(calc_handle * handle, files_var_entry * file); +HPEXPORT int HPCALL calc_prime_r_send_file(calc_handle * handle); + +HPEXPORT int HPCALL calc_prime_s_recv_file(calc_handle * handle, files_var_entry * file); +HPEXPORT int HPCALL calc_prime_r_recv_file(calc_handle * handle, files_var_entry ** out_file); + +HPEXPORT int HPCALL calc_prime_s_recv_backup(calc_handle * handle); +HPEXPORT int HPCALL calc_prime_r_recv_backup(calc_handle * handle, files_var_entry *** out_vars); + +HPEXPORT int HPCALL calc_prime_s_send_key(calc_handle * handle, uint32_t code); +HPEXPORT int HPCALL calc_prime_r_send_key(calc_handle * handle); +HPEXPORT int HPCALL calc_prime_s_send_keys(calc_handle * handle, const uint8_t * data, uint32_t size); +HPEXPORT int HPCALL calc_prime_r_send_keys(calc_handle * handle); + +HPEXPORT int HPCALL calc_prime_s_send_chat(calc_handle * handle, const uint16_t * data, uint32_t size); +HPEXPORT int HPCALL calc_prime_r_send_chat(calc_handle * handle); + +HPEXPORT int HPCALL calc_prime_r_recv_chat(calc_handle * handle, uint16_t ** out_data, uint32_t * out_size); + +#endif diff --git a/libhpcalcs/src/prime_rpkt.c b/libhpcalcs/src/prime_rpkt.c new file mode 100644 index 0000000..3f5eab9 --- /dev/null +++ b/libhpcalcs/src/prime_rpkt.c @@ -0,0 +1,103 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file prime_rpkt.c Calcs: Prime raw packets. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "internal.h" +#include "logging.h" +#include "error.h" +#include "utils.h" + +#include +#include +#include +#include + +HPEXPORT int HPCALL prime_send(calc_handle * handle, prime_raw_hid_pkt * pkt) { + int res; + if (handle != NULL && pkt != NULL) { + cable_handle * cable = handle->cable; + if (cable != NULL) { + hexdump("OUT", pkt->data, pkt->size, 2); + res = hpcables_cable_send(cable, pkt->data, pkt->size); + if (res == ERR_SUCCESS) { + hpcalcs_info("%s: send succeeded", __FUNCTION__); + } + else { + hpcalcs_error("%s: send failed", __FUNCTION__); + } + } + else { + res = ERR_CALC_NO_CABLE; + hpcalcs_error("%s: cable is NULL", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL prime_recv(calc_handle * handle, prime_raw_hid_pkt * pkt) { + int res; + if (handle != NULL && pkt != NULL) { + cable_handle * cable = handle->cable; + if (cable != NULL) { + uint8_t * data; + data = (hpcalcs_alloc_funcs.malloc)(sizeof(pkt->data)); + if (data != NULL) { + res = hpcables_cable_recv(cable, &data, &pkt->size); + hexdump("IN", data, pkt->size, 2); + if (res == ERR_SUCCESS) { + //hpcalcs_info("%s: recv succeeded", __FUNCTION__); + memcpy(pkt->data, data, sizeof(pkt->data)); + } + else { + hpcalcs_warning("%s: recv failed", __FUNCTION__); + } + (hpcalcs_alloc_funcs.free)(data); + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: failed to allocate buffer", __FUNCTION__); + } + } + else { + res = ERR_CALC_NO_CABLE; + hpcalcs_error("%s: cable is NULL", __FUNCTION__); + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} diff --git a/libhpcalcs/src/prime_vpkt.c b/libhpcalcs/src/prime_vpkt.c new file mode 100644 index 0000000..a574966 --- /dev/null +++ b/libhpcalcs/src/prime_vpkt.c @@ -0,0 +1,278 @@ +/* libhpcalcs - hand-helds support library + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file prime_vpkt.c Calcs: Prime virtual packets. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "internal.h" +#include "logging.h" +#include "error.h" + +#include "prime_cmd.h" + +#include +#include +#include + +// ----------------------------------------------- +// Calcs - HP Prime virtual packets +// ----------------------------------------------- + + +HPEXPORT prime_vtl_pkt * HPCALL prime_vtl_pkt_new(uint32_t size) { + prime_vtl_pkt * pkt = (prime_vtl_pkt *)(hpcalcs_alloc_funcs.malloc)(sizeof(*pkt)); + + if (pkt != NULL) { + pkt->size = size; + if (size != 0) { + pkt->data = (uint8_t *)(hpcalcs_alloc_funcs.calloc)(size, sizeof(*pkt->data)); + + if (pkt->data == NULL) { + (hpcalcs_alloc_funcs.free)(pkt); + pkt = NULL; + } + } + } + + return pkt; +} + +HPEXPORT prime_vtl_pkt * HPCALL prime_vtl_pkt_new_with_data_ptr(uint32_t size, uint8_t * data) { + prime_vtl_pkt * pkt = (prime_vtl_pkt *)(hpcalcs_alloc_funcs.malloc)(sizeof(*pkt)); + + if (pkt != NULL) { + pkt->size = size; + pkt->data = data; + } + + return pkt; +} + +HPEXPORT void HPCALL prime_vtl_pkt_del(prime_vtl_pkt * pkt) { + if (pkt != NULL) { + (hpcalcs_alloc_funcs.free)(pkt->data); + (hpcalcs_alloc_funcs.free)(pkt); + } + else { + hpcalcs_error("%s: pkt is NULL", __FUNCTION__); + } +} + +HPEXPORT int HPCALL prime_send_data(calc_handle * handle, prime_vtl_pkt * pkt) { + int res; + if (handle != NULL && pkt != NULL) { + prime_raw_hid_pkt raw; + uint32_t i, q, r; + uint32_t offset = 0; + uint8_t pkt_id = 0; + + memset((void *)&raw, 0, sizeof(raw)); + q = (pkt->size) / (PRIME_RAW_HID_DATA_SIZE - 1); + r = (pkt->size) % (PRIME_RAW_HID_DATA_SIZE - 1); + + hpcalcs_info("%s: q:%" PRIu32 "\tr:%" PRIu32, __FUNCTION__, q, r); + + for (i = 1; i <= q; i++) { + raw.size = PRIME_RAW_HID_DATA_SIZE + 1; + raw.data[1] = pkt_id; + memcpy(raw.data + 2, pkt->data + offset, PRIME_RAW_HID_DATA_SIZE - 1); + offset += PRIME_RAW_HID_DATA_SIZE - 1; + + res = prime_send(handle, &raw); + if (res) { + hpcalcs_info("%s: send %" PRIu32 " failed", __FUNCTION__, i); + r = 0; + break; + } + else { + hpcalcs_info("%s: send %" PRIu32 " succeeded", __FUNCTION__, i); + } + + // Increment packet ID, which seems to be necessary for computer -> calc packets + pkt_id++; + if (pkt_id == 0xFF) { + pkt_id = 0; // Skip 0xFF, which is used for other purposes. + } + } + + if (r || !pkt->size) { + raw.size = r + 2; + raw.data[1] = pkt_id; + memcpy(raw.data + 2, pkt->data + offset, r); + + res = prime_send(handle, &raw); + if (res) { + hpcalcs_info("%s: send remaining failed", __FUNCTION__); + } + else { + hpcalcs_info("%s: send remaining succeeded", __FUNCTION__); + } + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL prime_recv_data(calc_handle * handle, prime_vtl_pkt * pkt) { + int res; + if (handle != NULL && pkt != NULL) { + prime_raw_hid_pkt raw; + uint32_t expected_size = 0; + uint32_t offset = 0; + uint32_t read_pkts_count = 0; + // WIP: reassembly. + + //size = pkt->size; + pkt->size = 0; + pkt->data = NULL; + + for(;;) { + memset(&raw, 0, sizeof(raw)); + res = prime_recv(handle, &raw); + if (res) { + hpcalcs_warning("%s: recv failed", __FUNCTION__); + break; + } + else { + //hpcalcs_info("%s: recv succeeded", __FUNCTION__); + } + //hpcalcs_info("%s: raw.size=%" PRIu32, __FUNCTION__, raw.size); + if (raw.size > 0) { + uint8_t * new_data; + + // Exclude those packets from reassembly (at least for screenshotting purposes, they seem to be spurious). + if (raw.data[0] == 0xFF) { + // TODO: investigate whether the second byte could indicate an error code ? + hpcalcs_error("%s: skipping packet starting with 0xFF", __FUNCTION__); + continue; + } + // Sanity check. The first byte is the sequence number. After reaching 0xFE. it wraps back to 0 (skipping 0xFF). + else if (raw.data[0] != ((read_pkts_count + (read_pkts_count / 0xFF)) & 0xFF)) { + res = ERR_CALC_PACKET_FORMAT; + hpcalcs_error("%s: packet out of sequence, got %d, expected %d", __FUNCTION__, (int)raw.data[0], read_pkts_count); + break; + } + + read_pkts_count++; + + // Over-read prevention (hopefully ^^) code: pre-set the expected size of the reply to the given command. + if (read_pkts_count == 1) { + res = prime_data_size(pkt->cmd, raw.data + 1, &expected_size); // +1: skip leading byte. + if (res != ERR_SUCCESS) { + break; + } + } + + pkt->size += raw.size - 1; + new_data = (hpcalcs_alloc_funcs.realloc)(pkt->data, pkt->size); + if (new_data != NULL) { + pkt->data = new_data; + // Skip first byte, which is usually 0x00. + memcpy(pkt->data + offset, &(raw.data[1]), raw.size - 1); + offset += raw.size - 1; + } + else { + res = ERR_MALLOC; + hpcalcs_error("%s: cannot reallocate memory", __FUNCTION__); + break; + } + } + + if (raw.size < PRIME_RAW_HID_DATA_SIZE) { + hpcalcs_info("%s: breaking due to short packet (1)", __FUNCTION__); + goto shorten_packet; + } + if (offset >= expected_size) { + hpcalcs_info("%s: breaking because the expected size was reached (2)", __FUNCTION__); +shorten_packet: + // Shorten packet. + if (expected_size <= pkt->size) { + hpcalcs_info("%s: shortening packet from %" PRIu32 " to %" PRIu32, __FUNCTION__, pkt->size, expected_size); + } + else { + hpcalcs_warning("%s: expected %" PRIu32 " bytes but only got %" PRIu32 " bytes, output corrupted", __FUNCTION__, expected_size, pkt->size); + } + pkt->data = (hpcalcs_alloc_funcs.realloc)(pkt->data, expected_size); + pkt->size = expected_size; + break; + } + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} + +HPEXPORT int HPCALL prime_data_size(uint8_t cmd, uint8_t * data, uint32_t * out_size) { + int res = ERR_SUCCESS; + if (data != NULL && out_size != NULL) { + switch (cmd) { + case CMD_PRIME_CHECK_READY: + // Single-packet reply. + *out_size = 1; + break; + case CMD_PRIME_GET_INFOS: + case CMD_PRIME_RECV_SCREEN: + case CMD_PRIME_RECV_BACKUP: + // Not supposed to receive REQ_FILE + case CMD_PRIME_RECV_FILE: + case CMD_PRIME_RECV_CHAT: + // Not supposed to receive SEND_KEY + // Not supposed to receive SET_DATE_TIME + // Expected size is embedded in reply. + if (data[1] == 0x01) { + if (cmd != data[0]) { + hpcalcs_warning("%s: command in packet %02X does not match the expected command %02X", __FUNCTION__, data[0], cmd); + } + + *out_size = (((uint32_t)(data[2])) << 24) | (((uint32_t)(data[3])) << 16) | (((uint32_t)(data[4])) << 8) | ((uint32_t)(data[5])); + *out_size += 6; // cmd + 0x01 + size. + } + else { + res = ERR_CALC_PACKET_FORMAT; + hpcalcs_error("%s: expected 0x01 as second data byte", __FUNCTION__); + } + break; + default: + // Not implemented. + *out_size = 0; + hpcalcs_error("%s: received unknown command %u, size undetermined, please report", __FUNCTION__, cmd); + break; + } + } + else { + res = ERR_INVALID_PARAMETER; + hpcalcs_error("%s: an argument is NULL", __FUNCTION__); + } + return res; +} diff --git a/libhpcalcs/src/type2str.c b/libhpcalcs/src/type2str.c new file mode 100644 index 0000000..838df43 --- /dev/null +++ b/libhpcalcs/src/type2str.c @@ -0,0 +1,83 @@ +/* libhpcalcs - hand-helds support library + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file type2str.c Files / cables / calcs: Type (usually enum) <-> string conversion functions. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "logging.h" +#include "error.h" + +#include +#include + +HPEXPORT const char * HPCALL hpcalcs_model_to_string(calc_model model) { + return hpfiles_model_to_string(model); +} + +HPEXPORT calc_model HPCALL hpcalcs_string_to_model(const char *str) { + return hpfiles_string_to_model(str); +} + +HPEXPORT const char * HPCALL hpcables_model_to_string(cable_model model) { + switch (model) { + case CABLE_NUL: return ""; + case CABLE_PRIME_HID: return "Prime (HID)"; + default: return "unknown"; + } +} + +HPEXPORT cable_model HPCALL hpcables_string_to_model(const char *str) { + if (str != NULL) { + if (!strcasecmp("Prime HID", str) || !strcasecmp("Prime_HID", str) || !strcasecmp("HP Prime HID", str)) { + return CABLE_PRIME_HID; + } + // else fall through. + } + return CABLE_NUL; +} + +HPEXPORT const char * HPCALL hpfiles_model_to_string(calc_model model) { + switch (model) { + case CALC_NONE: return ""; + case CALC_PRIME: return "Prime"; + default: return "unknown"; + } +} + +HPEXPORT calc_model HPCALL hpfiles_string_to_model(const char *str) { + if (str != NULL) { + if (!strcasecmp("Prime", str) || !strcasecmp("HP Prime", str)) { + return CALC_PRIME; + } + // else fall through. + } + return CALC_NONE; +} diff --git a/libhpcalcs/src/typesprime.c b/libhpcalcs/src/typesprime.c new file mode 100644 index 0000000..91626b5 --- /dev/null +++ b/libhpcalcs/src/typesprime.c @@ -0,0 +1,192 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file typesprime.c Files: Prime file types and utility functions. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "typesprime.h" +#include "logging.h" +#include "error.h" + +#include +#include +// For path splitting. +#ifndef _WIN32 +#include +#include +#else +#include +#include +#endif + +const char * PRIME_CONST[][3] = { + { "SETTINGS", "", "Settings" }, // The extension is embedded in the file name. + { "", "unknown", "Unknown" }, + { "APP", "hpapp", "Application" }, + { "LIST", "hplist", "List" }, + { "MATRIX", "hpmatrix", "Matrix" }, + { "NOTE", "hpnote", "Note" }, + { "PRGM", "hpprgm", "Program" }, + { "APPNOTE", "hpappnote", "App Note" }, // XXX Tentative + { "APPPRGM", "hpappprgm", "App Program" }, // XXX Tentative + { "COMPLEX", "hpcomplex", "Complex" }, // Extension synthetized, not found with the connectivity kit or emulator ? + { "REAL", "hpreal", "Real" }, // Extension synthetized, not found with the connectivity kit or emulator ? + { "TESTMODECONFIG", "", "Real" }, // The extension is embedded in the file name. + { NULL, NULL, NULL } +}; + +const char * prime_vartype2str(uint8_t type) { + const char * res = "unknown"; + if (type < sizeof(PRIME_CONST)/sizeof(PRIME_CONST[0]) - 1) { + res = PRIME_CONST[type][0]; + } + hpfiles_debug("%s: returning %s", __FUNCTION__, res); + return res; +} + +uint8_t prime_str2vartype(const char * type) { + uint8_t res = PRIME_TYPE_UNKNOWN; + for (uint32_t i = 0; i < sizeof(PRIME_CONST)/sizeof(PRIME_CONST[0]) - 1; i++) { + if (!strcasecmp(PRIME_CONST[i][0], type)) { + res = i; + break; + } + } + hpfiles_debug("%s: returning %" PRIu8, __FUNCTION__, res); + return res; +} + +const char * prime_byte2fext(uint8_t type) { + const char * res = "unknown"; + if (type < sizeof(PRIME_CONST)/sizeof(PRIME_CONST[0]) - 1) { + res = PRIME_CONST[type][1]; + } + hpfiles_debug("%s: returning %s", __FUNCTION__, res); + return res; +} + +uint8_t prime_fext2byte(const char * type) { + uint8_t res = PRIME_TYPE_UNKNOWN; + for (uint32_t i = 0; i < sizeof(PRIME_CONST)/sizeof(PRIME_CONST[0]) - 1; i++) { + if (!strcasecmp(PRIME_CONST[i][1], type)) { + res = i; + break; + } + } + hpfiles_debug("%s: returning %" PRIu8, __FUNCTION__, res); + return res; +} + +const char * prime_byte2desc(uint8_t type) { + const char * res = "Unknown"; + if (type < sizeof(PRIME_CONST)/sizeof(PRIME_CONST[0]) - 1) { + res = PRIME_CONST[type][2]; + } + hpfiles_debug("%s: returning %s", __FUNCTION__, res); + return res; +} + +uint8_t prime_filename2byte(const char * filepath) { + uint8_t res = PRIME_TYPE_UNKNOWN; + prime_parsefilename(filepath, &res, NULL); + hpfiles_debug("%s: returning %" PRIu8, __FUNCTION__, res); + return res; +} + +int prime_parsesplitfilename(char * file, char * extension, uint8_t * out_type, char ** out_calcfilename) { + int res = ERR_FILE_FILENAME; + uint8_t type = PRIME_TYPE_UNKNOWN; + // The way to get the basename and file extension is platform-dependent, obviously... + hpfiles_info("%s: file:\"%s\" extension:\"%s\"", __FUNCTION__, file, extension); + if ( !strcmp(file, "calc.settings") + || !strcmp(file, "settings") + || !strcmp(file, "cas.settings") + ) { + type = PRIME_TYPE_SETTINGS; + } + else if (!strcmp(file, "testmodes.hptestmodes")) { + type = PRIME_TYPE_TESTMODECONFIG; + } + else { + if (extension != NULL && extension[0] == '.') { + type = prime_fext2byte(extension + 1); // Skip '.' + } + else { + hpfiles_error("%s: extension not found in filepath, unhandled type", __FUNCTION__); + } + } + if (type != PRIME_TYPE_UNKNOWN) { + res = ERR_SUCCESS; + *out_type = type; + if (out_calcfilename != NULL) { + char * calcfilename = strdup(file); +#ifndef _WIN32 + if (calcfilename != NULL) { + extension = strrchr(calcfilename, '.'); + if (extension != NULL) { + *extension = 0; // Strip extension. + } + } +#endif + *out_calcfilename = calcfilename; + } + } + return res; +} + +int prime_parsefilename(const char * filepath, uint8_t * out_type, char ** out_calcfilename) { + // The way to get the basename and file extension is platform-dependent, obviously... +#ifndef _WIN32 + int res = ERR_FILE_FILENAME; + char * duplicated = strdup(filepath); + char * file; + char * extension; + if (duplicated != NULL) { + file = basename(duplicated); + if (file != NULL) { + extension = strrchr(file, '.'); + res = prime_parsesplitfilename(file, extension, out_type, out_calcfilename); + } + free(duplicated); + } + else { + res = ERR_MALLOC; + hpfiles_debug("%s: failed to duplicate filepath", __FUNCTION__); + } +#else + int res; + char file[_MAX_FNAME + 1]; + char extension[_MAX_EXT + 1]; + _splitpath(filepath, NULL /* drive */, NULL /* dir */, file, extension); + res = prime_parsesplitfilename(file, extension, out_type, out_calcfilename); +#endif + + hpfiles_debug("%s: returning %d", __FUNCTION__, res); + return res; +} diff --git a/libhpcalcs/src/typesprime.h b/libhpcalcs/src/typesprime.h new file mode 100644 index 0000000..5cf7d26 --- /dev/null +++ b/libhpcalcs/src/typesprime.h @@ -0,0 +1,69 @@ +/* + * libhpfiles: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file typesprime.h Files: Prime file types and utility functions. + */ + +#ifndef __HPLIBS_FILES_TYPESPRIME_H__ +#define __HPLIBS_FILES_TYPESPRIME_H__ + +#define PRIME_TYPE_SETTINGS (0x00) +// 0x01 ? +#define PRIME_TYPE_APP (0x02) +#define PRIME_TYPE_LIST (0x03) // variables L0-L9, for instance +#define PRIME_TYPE_MATRIX (0x04) // variables M0-M9, for instance +#define PRIME_TYPE_NOTE (0x05) +#define PRIME_TYPE_PRGM (0x06) // programs with identical data are sent twice during backup ?? +#define PRIME_TYPE_APPNOTE (0x07) // XXX Tentative +#define PRIME_TYPE_APPPRGM (0x08) // XXX Tentative +#define PRIME_TYPE_COMPLEX (0x09) // variables Z0-Z9, for instance +#define PRIME_TYPE_REAL (0x0A) // variables A-Z, 0x3B8 (theta), for instance +#define PRIME_TYPE_TESTMODECONFIG (0x0B) +#define PRIME_TYPE_UNKNOWN (0xFF) + +//! Return the string corresponding to the file type ID +const char * prime_vartype2str(uint8_t type); + +//! Return the type ID corresponding to the string +uint8_t prime_str2vartype(const char * type); + +//! Return the file extension corresponding to the value +const char * prime_byte2fext(uint8_t type); + +//! Return the type value corresponding to the file extension +uint8_t prime_fext2byte(const char * type); + +//! Return the description corresponding to the value +const char * prime_byte2desc(uint8_t type); + +//! Return the type value corresponding to the file path +uint8_t prime_filename2byte(const char * filepath); + +//! Parse the file name + extension and determines the type value and calculator-side filename +int prime_parsesplitfilename(char * file, char * extension, uint8_t * out_type, char ** out_calcfilename); + +//! Parse the file path and determines the type value and calculator-side filename +int prime_parsefilename(const char * filepath, uint8_t * out_type, char ** out_calcfilename); + +#endif diff --git a/libhpcalcs/src/utils.c b/libhpcalcs/src/utils.c new file mode 100644 index 0000000..c7629b5 --- /dev/null +++ b/libhpcalcs/src/utils.c @@ -0,0 +1,114 @@ +/* + * libhpfiles, libhpcables, libhpcalcs - hand-helds support library + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file utils.c Files / Cables / Calcs: utility functions, e.g. UTF-16LE handling. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "internal.h" +#include "utils.h" +#include "logging.h" + +#include +#include + +uint32_t char16_strlen(char16_t * str) { + uint32_t i = 0; + if (str != NULL) { + while (*str) { + i++; + str++; + } + } + return i; +} + +char16_t * char16_strncpy(char16_t * dst, const char16_t * src, uint32_t n) { + if (dst != NULL && src != NULL) { + uint32_t i = 0; + char16_t c = *src; + while (i < n && c != 0) { + *dst++ = c; + src++; + c = *src; + } + } + return dst; +} + +void hexdump(const char * direction, uint8_t *data, uint32_t size, uint32_t level) +{ + if (size > 0) { + if (level == 1) { + char str[64]; + + hpcalcs_debug("Dumping %s packet with size %" PRIu32, direction, size); + str[0] = 0; + if (size <= 12) + { + uint32_t i; + str[0] = ' '; str[1] = ' '; str[2] = ' '; str[3] = ' '; + + for (i = 0; i < size; i++) + { + sprintf(&str[3*i+4], "%02X ", data[i]); + } + } + else + { + sprintf(str, " %02X %02X %02X %02X %02X ..... %02X %02X %02X %02X %02X", + data[0], data[1], data[2], data[3], data[4], + data[size-5], data[size-4], data[size-3], data[size-2], data[size-1]); + } + hpcalcs_debug(str); + } + else if (level == 2) { + const int step = 16; + char str[4 + 3 * step + 1]; + uint32_t i, j; + + hpcalcs_debug("Dumping %s packet with size %" PRIu32, direction, size); + + str[0] = ' '; + str[1] = ' '; + str[2] = ' '; + str[3] = ' '; + str[sizeof(str) - 1] = 0; + + for (i = j = 0; i < size; i++, j++) { + if (i && !(i % step)) { + hpcalcs_debug(str); + j = 0; + } + + sprintf(&str[3*j+4], "%02X ", data[i]); + } + hpcalcs_debug(str); + } + } +} diff --git a/libhpcalcs/src/utils.h b/libhpcalcs/src/utils.h new file mode 100644 index 0000000..cdea8cf --- /dev/null +++ b/libhpcalcs/src/utils.h @@ -0,0 +1,38 @@ +/* + * libhpfiles, libhpcables, libhpcalcs - hand-helds support library + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file utils.h Files / Cables / Calcs: utility functions, e.g. UTF-16LE handling. + */ + +#ifndef __HPLIBS_UTILS_H__ +#define __HPLIBS_UTILS_H__ + +//! Plain C equivalent of char_traits::length. +uint32_t char16_strlen(char16_t * str); +//! strncpy applied to char16_t. +char16_t * char16_strncpy(char16_t * dst, const char16_t * src, uint32_t n); +//! Hex dumping function. +void hexdump(const char * direction, uint8_t *data, uint32_t size, uint32_t level); + +#endif diff --git a/libhpcalcs/tests/test_hpcalcs.c b/libhpcalcs/tests/test_hpcalcs.c new file mode 100644 index 0000000..7bdbcc2 --- /dev/null +++ b/libhpcalcs/tests/test_hpcalcs.c @@ -0,0 +1,816 @@ +/* + * libhpcalcs: hand-helds support libraries. + * Copyright (C) 2013 Lionel Debroux + * Code patterns and snippets borrowed from libticables & libticalcs: + * Copyright (C) 1999-2009 Romain Livin + * Copyright (C) 2009-2013 Lionel Debroux + * Copyright (C) 1999-2013 libti* contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * \file test_hpcalcs.c Calcs: Example / testing code, which can be considered authoritative. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../src/hpfiles.h" +#include "../src/hpcables.h" +#include "../src/hpcalcs.h" +#include "../src/hpopers.h" +#include "../src/prime_cmd.h" + +#undef VERSION +#define VERSION "Test program" + +#ifdef _WIN32 +static FILE * log_file = NULL; +#endif + +// Injecting memory allocation functions into the library is optional, the library will default to those if you don't. +static const hplibs_malloc_funcs alloc_funcs = { + .malloc = malloc, + .calloc = calloc, + .realloc = realloc, + .free = free +}; + +// Windows' terminal is extremely slow, cannot print the logging traces there. +#ifdef _WIN32 + +static void open_log_file(void) { + if (log_file == NULL) { + log_file = fopen("trace.txt", "w+b"); + if (log_file != NULL) { + time_t curtime = time(NULL); + fprintf(log_file, "Opening log file at %s", ctime(&curtime)); + } + } +} + +// Output logging traces to a file. +static void output_log_callback(const char * format, va_list args) { + open_log_file(); + if (log_file != NULL) { + vfprintf(log_file, format, args); + fflush(log_file); + } +} + +static void output_log(FILE *f, const char * format, ...) { + char str[256]; + va_list args; + va_start(args, format); + vsnprintf(str, 256, format, args); + str[255] = 0; + fprintf(f, "%s", str); + open_log_file(); + if (log_file != NULL) { + fprintf(log_file, "%s", str); + } +} + +#else + +// Using args twice, once for printing to stdout and once for printing to a file, triggers crashes. +// Therefore, let's have this function print only to stdout. +// Should there be a need to print to a file, on non-Windows, people can rely on "tee". +static void output_log_callback(const char * format, va_list args) { + vprintf(format, args); +} + +static void output_log(FILE *f, const char * format, ...) { + char str[256]; + va_list args; + va_start(args, format); + vsnprintf(str, 256, format, args); + str[255] = 0; + fprintf(f, "%s", str); +} + +#endif + +// Unconditionally output to stdout, on all platforms. +static void output_log_callback_stdout(const char * format, va_list args) { + vprintf(format, args); +} + + +// NOTE: this triplet of crude routines is just for demo and testing purposes !! +// In the general case, a proper i18n library (not offered by the C standard library) should be used ! +static void crude_convert_UTF16LE_to_8bit(const char16_t * input, char * output) { + const char * in_ptr = (const char *)input; + char16_t chr = 0; + do { + chr = ((char16_t)*in_ptr) | (((char16_t)*(in_ptr + 1)) << 8); + in_ptr += 2; + if (chr & 0xFF00) { + *output++ = '_'; // Mangle characters with high byte set... + } + else { + *output++ = (char)(chr & 0xFF); + } + } while (chr != 0); +} + +static void crude_convert_8bit_to_UTF16LE(const char * input, char16_t * output) { + char chr = 0; + do { + chr = *input++; + *((char *)output) = chr; + *(((char *)output) + 1) = 0x00; + output++; + } while (chr != 0); +} + +static void crude_convert_wchar_t_to_UTF16LE(const wchar_t * input, char16_t * output) { + wchar_t chr = 0; + do { + chr = *input++; + *output++ = (char16_t)chr; + } while (chr != 0); +} + +static void produce_output_file(calc_handle * handle, files_var_entry * entry) { + char filename[FILES_VARNAME_MAXLEN + 13]; + FILE * f; + const char * extension; + + output_log(stdout, "test_hpcalcs: Receive file success\n"); + hpfiles_ve_display(entry); + crude_convert_UTF16LE_to_8bit(entry->name, filename); + if (entry->invalid) { + output_log(stdout, "test_hpcalcs: NOTE: the data for file %s is corrupted (packet loss in transfer) !\n", filename); + } + extension = hpfiles_vartype2fext(hpcalcs_get_model(handle), entry->type); + if (extension[0] != 0) { + strcat(filename, "."); + strcat(filename, extension); + } + f = fopen(filename, "w+b"); + if (f != NULL) { + fwrite(entry->data, 1, entry->size, f); + fclose(f); + } + else { + output_log(stdout, "test_hpcalcs: Cannot open file for writing !\n"); + } +} + +static int is_ready(calc_handle * handle) { + int res; + uint8_t * data; + uint32_t size; + + res = hpcalcs_calc_check_ready(handle, &data, &size); + if (res == 0) { + output_log(stdout, "Check ready success\n"); + // TODO: do something with data & size. + } + else { + output_log(stdout, "hpcalcs_calc_check_ready failed\n"); + } + + return res; +} + +static int get_infos(calc_handle * handle) { + int res; + calc_infos infos; + + res = hpcalcs_calc_get_infos(handle, &infos); + if (res == 0) { + output_log(stdout, "Get infos success\n"); + // TODO: do something with infos. + } + else { + output_log(stdout, "hpcalcs_calc_get_infos failed\n"); + } + + return res; +} + +static int set_date_time(calc_handle * handle) { + int res; + + res = hpcalcs_calc_set_date_time(handle, time(NULL)); + if (res == 0) { + output_log(stdout, "Set date time success\n"); + } + else { + output_log(stdout, "hpcalcs_calc_set_date_time failed\n"); + } + + return res; +} + +static int recv_screen(calc_handle * handle) { + int res = 0; + uint8_t * data; + uint32_t size; + unsigned int format; + int err; + + output_log(stdout, "\nChoose a format (for Prime, usually 8 to 11): "); + + err = scanf("%u", &format); + if (err >= 1) { + char filename[1024]; + filename[0] = 0; + output_log(stdout, "\n%u\nEnter output filename: ", format); + err = scanf("%1023s", filename); + if (err >= 1) { + output_log(stdout, "\n%s\n", filename); + res = hpcalcs_calc_recv_screen(handle, format, &data, &size); + if (res == 0 && data != NULL) { + FILE * f; + output_log(stdout, "Receive screenshot success\n"); + f = fopen(filename, "w+b"); + if (f != NULL) { + fwrite(data, 1, size, f); + fclose(f); + } + else { + output_log(stdout, "Cannot open file for writing !\n"); + } + } + else { + output_log(stdout, "hpcalcs_calc_recv_screen failed\n"); + } + } + else { + fflush(stdin); + output_log(stdout, "Canceled\n"); + } + } + else { + fflush(stdin); + output_log(stdout, "Canceled\n"); + } + + return res; +} + +/*// On GCC 4.7+ and Clang, we can use the standard u"FOO" construct; otherwise, use L"x". +#if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ <= 4) && (__GNUC_MINOR__ < 7)) +#define UTF16(x) L##x +#else +#define UTF16(x) u##x +#endif*/ + +#define xstr(s) str(s) +#define str(s) #s + +static int send_file(calc_handle * handle) { + int res = 0; + int err; + files_var_entry * entry = NULL; + char filename[FILES_VARNAME_MAXLEN + 1]; + + output_log(stdout, "\nEnter input filename: "); + err = scanf("%" xstr(FILES_VARNAME_MAXLEN) "s", filename); + if (err >= 1) { + FILE * f = fopen(filename, "rb"); + if (f != NULL) { + uint32_t size; + uint8_t type; + fseek(f, 0, SEEK_END); + size = (uint32_t)ftell(f); + fseek(f, 0, SEEK_SET); + output_log(stdout, "Input file has size %" PRIu32 " (%" PRIx32 ")\n", size, size); + entry = hpfiles_ve_create_with_size(size); + if (entry != NULL) { + char * calcfilename = NULL; + if (!hpfiles_parsefilename(hpcalcs_get_model(handle), filename, &type, &calcfilename)) { + if (type != HPLIBS_FILE_TYPE_UNKNOWN && calcfilename != NULL) { + entry->type = type; + if (fread(entry->data, 1, size, f) == size) { + crude_convert_8bit_to_UTF16LE(calcfilename, entry->name); + // We can at last send the file ! + res = hpcalcs_calc_send_file(handle, entry); + if (res == 0 && entry != NULL) { + output_log(stdout, "hpcalcs_calc_send_file succeeded\n"); + } + else { + output_log(stdout, "hpcalcs_calc_send_file failed\n"); + } + } + else { + output_log(stdout, "Reading input file failed, aborted\n"); + } + free(calcfilename); + } + else { + output_log(stdout, "Unable to determine file type or calc filename, aborted (please report the bug !)\n"); + } + } + else { + output_log(stdout, "Unable to parse filename, aborted (please report the bug !)\n"); + } + hpfiles_ve_delete(entry); + } + else { + output_log(stdout, "Cannot create entry, aborted\n"); + } + } + else { + output_log(stdout, "Cannot open input file, aborted\n"); + } + } + else { + fflush(stdin); + output_log(stdout, "Canceled\n"); + } + + return res; +} + +static int recv_file(calc_handle * handle) { + int res = 0; + int err; + files_var_entry request; + files_var_entry * entry; + char typestr[11]; + wchar_t filename[FILES_VARNAME_MAXLEN + 1]; + + memset((void *)&request, 0, sizeof(request)); + output_log(stdout, "\nEnter input filename (without computer-side extension): "); + err = scanf("%" xstr(FILES_VARNAME_MAXLEN) "ls", filename); + if (err >= 1) { + output_log(stdout, "Enter file type: "); + + err = scanf("%10s", typestr); + if (err >= 1) { + uint8_t type = hpfiles_str2vartype(hpcalcs_get_model(handle), typestr); + if (type != HPLIBS_FILE_TYPE_UNKNOWN) { + /*const char * fext = hpfiles_vartype2fext(hpcalcs_get_model(handle), type); + if (fext != NULL && fext[0] != 0) { + wcscat(request.name, L"."); + crude_convert_8bit_to_UTF16LE(fext, request.name + wcslen(request.name) + 1); + }*/ + crude_convert_wchar_t_to_UTF16LE(filename, request.name); + request.type = type; + res = hpcalcs_calc_recv_file(handle, &request, &entry); + output_log(stdout, "hpcalcs_calc_recv_file finished\n"); + if (res == 0 && entry != NULL) { + produce_output_file(handle, entry); + hpfiles_ve_delete(entry); + } + else { + output_log(stdout, "hpcalcs_calc_recv_file failed\n"); + } + } + else { + output_log(stdout, "Unable to determine file type from stringe, aborted (please report the bug !)\n"); + } + } + else { + fflush(stdin); + output_log(stdout, "Canceled\n"); + } + } + else { + fflush(stdin); + output_log(stdout, "Canceled\n"); + } + + return res; +} + +static int recv_backup(calc_handle * handle) { + int res; + files_var_entry ** entries; + + res = hpcalcs_calc_recv_backup(handle, &entries); + if (res != 0) { + output_log(stdout, "hpcalcs_calc_recv_backup failed\nWill nevertheless attempt to salvage data, if possible\n"); + } + if (entries != NULL) { + files_var_entry ** ptr = entries; + while (*ptr != NULL) { + produce_output_file(handle, *ptr++); + } + hpfiles_ve_delete_array(entries); + } + else { + output_log(stdout, "hpcalcs_calc_recv_backup returned NULL entries, no data available\n"); + } + + return res; +} + +static int send_key(calc_handle * handle) { + int res = 0; + int err; + unsigned int type; + + output_log(stdout, "Enter key ID: "); + err = scanf("%u", &type); + if (err >= 1) { + res = hpcalcs_calc_send_key(handle, type); + if (res == 0) { + output_log(stdout, "hpcalcs_calc_send_key succeeded\n"); + } + else { + output_log(stdout, "hpcalcs_calc_send_key failed\n"); + } + } + else { + fflush(stdin); + output_log(stdout, "Canceled\n"); + } + + return res; +} + +#define STRBUF_SIZE 1024 +#define DATA_SIZE 512 +#define SEPARATORS ", \t\n" + +static int send_keys(calc_handle * handle) { + int res = 0; + int err; + char str[STRBUF_SIZE]; + uint8_t data[DATA_SIZE]; + uint32_t count = 0; + + fflush(stdin); + output_log(stdout, "Enter key IDs, separated by commas or spaces:"); + err = scanf("%" xstr(STRBUF_SIZE) "[0-9xa-fA-F, ]", str); + if (err >= 1) { + char * token = strtok(str, SEPARATORS); + if (token != NULL) { + int success = 1; + do { + unsigned long val; + char * endptr; + + errno = 0; + val = strtoul(token, &endptr, 0); + + if ((errno == ERANGE && val == ULONG_MAX) || (errno != 0 && val == 0)) { + output_log(stdout, "Item %" PRIu32 " is out of range, aborting\n", count); + success = 0; + break; + } + + if (endptr == str) { + output_log(stdout, "Item %" PRIu32 " is no number, aborting\n", count); + success = 0; + break; + } + + data[count++] = (uint8_t)val; + + token = strtok(NULL, SEPARATORS); + + } while (token != NULL); + + if (success) { + res = hpcalcs_calc_send_keys(handle, data, count); + if (res == 0) { + output_log(stdout, "hpcalcs_calc_send_keys succeeded\n"); + } + else { + output_log(stdout, "hpcalcs_calc_send_keys failed\n"); + } + } + } + else { + fflush(stdin); + output_log(stdout, "Failed to parse, canceled\n"); + } + } + else { + fflush(stdin); + output_log(stdout, "Canceled\n"); + } + + return res; +} + +#undef SEPARATORS +#undef DATA_SIZE +#undef STRBUF_SIZE + +static int send_chat(calc_handle * handle) { + int res = 0; + static const uint16_t chat_data[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 }; + + res = hpcalcs_calc_send_chat(handle, chat_data, sizeof(chat_data)); + if (res == 0) { + output_log(stdout, "hpcalcs_calc_send_chat succeeded\n"); + } + else { + output_log(stdout, "hpcalcs_calc_send_chat failed\n"); + } + + return res; +} + +static int recv_chat(calc_handle * handle) { + int res = 0; + uint32_t size; + uint16_t * data; + + res = hpcalcs_calc_recv_chat(handle, &data, &size); + if (res == 0) { + output_log(stdout, "hpcalcs_calc_recv_chat succeeded\n"); + // TODO: do something with chat data. + } + else { + output_log(stdout, "hpcalcs_calc_recv_chat failed\n"); + } + + return res; +} + +static int vpkt_send_experiments(calc_handle * handle) { + int res = 0; + int err; + unsigned int id; + + output_log(stdout, "Enter command ID: "); + err = scanf("%u", &id); + if (err >= 1) { + prime_vtl_pkt * pkt = prime_vtl_pkt_new(2); + if (pkt != NULL) { + uint8_t * ptr; + + pkt->cmd = (uint8_t)id; + ptr = pkt->data; + *ptr++ = (uint8_t)id; + res = prime_send_data(handle, pkt); + + if (res == 0) { + output_log(stdout, "prime_send_data succeeded\n"); + } + else { + output_log(stdout, "prime_send_data failed\n"); + } + + prime_vtl_pkt_del(pkt); + } + else { + output_log(stdout, "%s: couldn't create packet", __FUNCTION__); + } + } + else { + fflush(stdin); + output_log(stdout, "Canceled\n"); + } + + return res; +} + +#define NITEMS 13 + +static const char *str_menu[NITEMS] = { + "Exit", + "Check whether calc is ready", + "Get calculator information", + "Set date and time", + "Get screenshot", + "Send file", + "Receive file", + "Receive backup", + "Send key (single key)", + "Send keys (multiple keys)", + "Send chat", + "Receive chat", + "Virtual packet send experiments" +}; + +typedef int (*FNCT_MENU) (calc_handle*); + +static const FNCT_MENU fnct_menu[NITEMS] = { + NULL, + is_ready, + get_infos, + set_date_time, + recv_screen, + send_file, + recv_file, + recv_backup, + send_key, + send_keys, + send_chat, + recv_chat, + vpkt_send_experiments +}; + +static const hpfiles_config hpfiles_cfg = { + .version = HPFILES_CONFIG_VERSION, + .log_callback = output_log_callback, + .alloc_funcs = &alloc_funcs +}; +static const hpcables_config hpcables_cfg = { + .version = HPCABLES_CONFIG_VERSION, + .log_callback = output_log_callback, + .alloc_funcs = NULL +}; +static const hpcalcs_config hpcalcs_cfg = { + .version = HPCALCS_CONFIG_VERSION, + .log_callback = output_log_callback, + .alloc_funcs = &alloc_funcs +}; +static const hpopers_config hpopers_cfg = { + .version = HPOPERS_CONFIG_VERSION, + .log_callback = output_log_callback, + .alloc_funcs = NULL +}; + +int main(int argc, char **argv) { + cable_model model1 = CABLE_NUL; + calc_model model2 = CALC_NONE; + cable_handle * cable; + calc_handle * calc; + int res = 1; + uint8_t * probed_cables = NULL; + + // Set stdout and stderr to unbuffered mode. + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + output_log(stdout, "Entering program\n"); + + // Init libraries + if (hpfiles_init(&hpfiles_cfg)) { + goto final_teardown; + } + if (hpcables_init(&hpcables_cfg)) { + goto final_teardown; + } + if (hpcalcs_init(&hpcalcs_cfg)) { + goto final_teardown; + } + if (hpopers_init(&hpopers_cfg)) { + goto final_teardown; + } + + output_log(stdout, "Supported cables: 0x%" PRIX32 "\n", hpcables_supported_cables()); + output_log(stdout, "Supported calcs: 0x%" PRIX32 "\n", hpcalcs_supported_calcs()); + + if (model1 == CABLE_NUL) { + // Probe cables and calculators. + res = hpcables_probe_cables(&probed_cables); + if (res == 0) { + output_log(stdout, "Found no usable cables (?!): exiting\n"); + res = 1; + goto final_teardown; + } + else if (res == 1) { + // This means that the null cable is the only usable cable. Fall through. + model1 = CABLE_NUL; + hpcables_probe_free(probed_cables); + } + else { + int err; + + output_log(stdout, "hpcables_probe_cables found %d cables\n", res); + hpcables_log_set_callback(output_log_callback_stdout); + hpcables_probe_display(probed_cables); + hpcables_log_set_callback(output_log_callback); + hpcables_probe_free(probed_cables); + + output_log(stdout, "Enter the ID of the cable you want to use: "); + + err = scanf("%u", &model1); + if (err < 1) { + fflush(stdin); + output_log(stdout, "Canceled, exiting program\n"); + res = 1; + goto final_teardown; + } + } + } + + if (model1 == CABLE_NUL) { + output_log(stdout, "NOTE: null cable selected, the program won't do much in the way of useful things !\n"); + } + + output_log(stdout, "Initialized libraries\n"); + + cable = hpcables_handle_new(model1); + if (cable == NULL) { + output_log(stdout, "hpcables_handle_new failed\n"); + res = 1; + goto final_teardown; + } + + res = hpcalcs_probe_calc(model1, &model2); + if (res != 0) { + output_log(stdout, "hpcalcs_probe_calc failed\n"); + res = 1; + goto del_cable; + } + + calc = hpcalcs_handle_new(model2); + if (calc == NULL) { + output_log(stdout, "hpcalcs_handle_new failed\n"); + res = 1; + goto del_cable; + } + + // attach cable to calc (and open cable) + res = hpcalcs_cable_attach(calc, cable); + if (res) { + res = 1; + goto del_calc; + } + + if (model1 == CABLE_NUL) { + output_log(stdout, "NOTE: null cable selected, the program won't do much in the way of useful things !\n"); + } + + if (model2 == CALC_NONE) { + output_log(stdout, "NOTE: null calculator selected, the program won't do much in the way of useful things !\n"); + } + + do + { + int i; + int err; + unsigned int choice; + + // Display menu + output_log(stdout, "Choose an action:\n"); + for(i = 0; i < NITEMS; i++) { + output_log(stdout, "%2i. %s\n", i, str_menu[i]); + } + output_log(stdout, "Your choice: "); + + err = scanf("%u", &choice); + if (err < 1) { + fflush(stdin); + continue; + } + output_log(stdout, "\n"); + + if (choice == 0) { + break; + } + + // Process choice + if (choice < (int)(sizeof(fnct_menu)/sizeof(fnct_menu[0])) && fnct_menu[choice]) { + err = fnct_menu[choice](calc); + if (err) { + char * s; + err = hplibs_error_get(err, &s); + if (s != NULL) { + output_log(stdout, "%d %s", err, s); + free(s); + } + else { + output_log(stdout, "%d \n", err); + } + } + } + output_log(stdout, "\n"); + + } while(1); + + // detach cable + res = hpcalcs_cable_detach(calc); + + // remove calc & cable +del_calc: + hpcalcs_handle_del(calc); +del_cable: + hpcables_handle_del(cable); + +final_teardown: + output_log(stdout, "Exiting program\n"); + hpopers_exit(); + hpcalcs_exit(); + hpcables_exit(); + hpfiles_exit(); + + output_log(stdout, "Goodbye world!\n"); + return res; +} diff --git a/libhpcalcs/tests/torture_hpcalcs.c b/libhpcalcs/tests/torture_hpcalcs.c new file mode 100644 index 0000000..a2e806d --- /dev/null +++ b/libhpcalcs/tests/torture_hpcalcs.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include +#include + +#define PRINTF(FUNCTION, TYPE, args...) \ +fprintf(stderr, "%d\t" TYPE "\n", i, FUNCTION(args)); i++ + +#define PRINTFVOID(FUNCTION, args...) \ +fprintf(stderr, "%d\n", i); FUNCTION(args); i++ + +#define INT "%d" +#define PTR "%p" +#define STR "\"%s\"" +#define VOID "" + +static void output_log_callback(const char *format, va_list args) { + vprintf(format, args); + fflush(stdout); +} + +int main(int argc, char **argv) { + int i = 1; + + hpfiles_init(NULL); + hpfiles_exit(); + + hpcables_init(NULL); + hpcables_exit(); + + hpcalcs_init(NULL); + hpcalcs_exit(); + + hpopers_init(NULL); + hpopers_exit(); + + return 0; +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..06f76d5 --- /dev/null +++ b/main.cpp @@ -0,0 +1,6 @@ +#include "main.h" + +main::main() +{ + +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..23f7e35 --- /dev/null +++ b/main.h @@ -0,0 +1,11 @@ +#ifndef MAIN_H +#define MAIN_H + + +class main +{ +public: + main(); +}; + +#endif // MAIN_H diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..49d64fc --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,14 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..a3948a9 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,22 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..6050363 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,24 @@ + + MainWindow + + + + 0 + 0 + 400 + 300 + + + + MainWindow + + + + + + + + + + + diff --git a/model.qmodel b/model.qmodel new file mode 100644 index 0000000..e070190 --- /dev/null +++ b/model.qmodel @@ -0,0 +1,55 @@ + + + + {fe28840b-a618-4a4d-ade6-3589798d4c2c} + + + + + + + + {c5070eb7-5f21-4a7f-a831-ee79fb344ca4} + + + model + + + + + + + {3fffd935-1b54-435e-ac46-2637a079e9a7} + + + + + + + + + + {3fffd935-1b54-435e-ac46-2637a079e9a7} + + + model + + + + + + + + + + + + + + + + + + + + diff --git a/qthpconnect.qrc b/qthpconnect.qrc new file mode 100644 index 0000000..90f4a83 --- /dev/null +++ b/qthpconnect.qrc @@ -0,0 +1,2 @@ + + diff --git a/texteditor.cpp b/texteditor.cpp new file mode 100644 index 0000000..5dbf702 --- /dev/null +++ b/texteditor.cpp @@ -0,0 +1,14 @@ +#include "texteditor.h" +#include "ui_texteditor.h" + +textEditor::textEditor(QWidget *parent) : + QDockWidget(parent), + ui(new Ui::textEditor) +{ + ui->setupUi(this); +} + +textEditor::~textEditor() +{ + delete ui; +} diff --git a/texteditor.h b/texteditor.h new file mode 100644 index 0000000..67bbcc2 --- /dev/null +++ b/texteditor.h @@ -0,0 +1,22 @@ +#ifndef TEXTEDITOR_H +#define TEXTEDITOR_H + +#include + +namespace Ui { +class textEditor; +} + +class textEditor : public QDockWidget +{ + Q_OBJECT + +public: + explicit textEditor(QWidget *parent = 0); + ~textEditor(); + +private: + Ui::textEditor *ui; +}; + +#endif // TEXTEDITOR_H diff --git a/treemodel.cpp b/treemodel.cpp new file mode 100644 index 0000000..e21b329 --- /dev/null +++ b/treemodel.cpp @@ -0,0 +1,6 @@ +#include "treemodel.h" + +treeModel::treeModel() +{ + +} diff --git a/treemodel.h b/treemodel.h new file mode 100644 index 0000000..6d79807 --- /dev/null +++ b/treemodel.h @@ -0,0 +1,12 @@ +#ifndef TREEMODEL_H +#define TREEMODEL_H + +#include + +class treeModel +{ +public: + treeModel(); +}; + +#endif // TREEMODEL_H \ No newline at end of file diff --git a/variableview.cpp b/variableview.cpp new file mode 100644 index 0000000..c2c8a38 --- /dev/null +++ b/variableview.cpp @@ -0,0 +1,14 @@ +#include "variableview.h" +#include "ui_variableview.h" + +variableView::variableView(QWidget *parent) : + QWidget(parent), + ui(new Ui::variableView) +{ + ui->setupUi(this); +} + +variableView::~variableView() +{ + delete ui; +} diff --git a/variableview.h b/variableview.h new file mode 100644 index 0000000..c89f59d --- /dev/null +++ b/variableview.h @@ -0,0 +1,22 @@ +#ifndef VARIABLEVIEW_H +#define VARIABLEVIEW_H + +#include + +namespace Ui { +class variableView; +} + +class variableView : public QWidget +{ + Q_OBJECT + +public: + explicit variableView(QWidget *parent = 0); + ~variableView(); + +private: + Ui::variableView *ui; +}; + +#endif // VARIABLEVIEW_H diff --git a/variableview.ui b/variableview.ui new file mode 100644 index 0000000..5ffce79 --- /dev/null +++ b/variableview.ui @@ -0,0 +1,22 @@ + + + + + + variableView + + + + 0 + 0 + 640 + 480 + + + + Form + + + + + diff --git a/vartablemodel.cpp b/vartablemodel.cpp new file mode 100644 index 0000000..4e7ee68 --- /dev/null +++ b/vartablemodel.cpp @@ -0,0 +1,6 @@ +#include "vartreemodel.h" + +varTreeModel::varTreeModel() +{ + +} diff --git a/vartablemodel.h b/vartablemodel.h new file mode 100644 index 0000000..ef61ea5 --- /dev/null +++ b/vartablemodel.h @@ -0,0 +1,11 @@ +#ifndef VARTREEMODEL_H +#define VARTREEMODEL_H + + +class varTreeModel +{ +public: + varTreeModel(); +}; + +#endif // VARTREEMODEL_H \ No newline at end of file