This commit is contained in:
Oliver Atkinson 2025-01-15 15:12:17 -07:00
commit a19475e7e6
10 changed files with 472 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

39
include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

16
platformio.ini Normal file
View File

@ -0,0 +1,16 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:nanoatmega328]
platform = atmelavr
board = nanoatmega328
framework = arduino
test_framework = unity
; build_flags = "-D UBRR1H"

140
src/cmd/cmd.cpp Normal file
View File

@ -0,0 +1,140 @@
#include <HardwareSerial.h>
#include "write.h"
Addr::Addr(InfoCommands cmd)
{
device_address = 0x36;
class_address = 0x74;
rw_flag = 0x01;
switch (cmd)
{
case Model:
subclass_address = 0x02;
break;
case FPGA_Ver:
subclass_address = 0x03;
break;
case FPGA_Comp_Time:
subclass_address = 0x04;
break;
case Module_Software_Ver:
subclass_address = 0x05;
break;
case Module_Software_Comp_Time:
subclass_address = 0x06;
break;
case Camera_Calibration_Ver_Time:
subclass_address = 0x0B;
break;
case ISP_Parameter_Ver:
subclass_address = 0x0C;
break;
case Init_State:
// TODO why is this one so different?
class_address = 0x7D;
subclass_address = 0x06;
rw_flag = 0x00;
}
}
Addr::Addr(FuncCommands cmd)
{
device_address = 0x36;
rw_flag = 0x00;
switch (cmd)
{
case Manual_Shutter_Calibration:
class_address = 0x7C;
subclass_address = 0x02;
break;
case Manual_Background_Correction:
class_address = 0x7C;
subclass_address = 0x03;
break;
case Automatic_Shutter_Control:
class_address = 0x7C;
subclass_address = 0x04;
break;
case Automatic_Shutter_Switching_Interval:
class_address = 0x7C;
subclass_address = 0x05;
break;
case Vignetting_Correction:
class_address = 0x7C;
subclass_address = 0x0C;
break;
case Brightness:
class_address = 0x78;
subclass_address = 0x02;
break;
case Contrast:
class_address = 0x78;
subclass_address = 0x03;
break;
case Digital_Enhancement:
class_address = 0x78;
subclass_address = 0x10;
break;
case Static_De_Noising:
class_address = 0x78;
subclass_address = 0x15;
break;
case Dynamic_De_Noising:
class_address = 0x78;
subclass_address = 0x16;
break;
case Defective_Pixel_Correction:
class_address = 0x78;
subclass_address = 0x1A;
break;
case Palette_Setting:
class_address = 0x78;
subclass_address = 0x20;
break;
case Factory_Reset:
class_address = 0x74;
subclass_address = 0x0F;
break;
case Save_Settings:
class_address = 0x74;
subclass_address = 0x10;
break;
case Mirroring:
class_address = 0x70;
subclass_address = 0x11;
break;
}
}
void command(Addr cmd, uint8_t data_in[], int data_len, uint8_t buffer[])
{
char begin = 0xF0;
char size = data_len + 4;
char end = 0xFF;
// GET CHECKSUM //////////////////////////////
// add all addresses + rw_flag + data and take the last 8 bits as the checksum
int all_data = 0;
all_data += cmd.device_address;
all_data += cmd.class_address;
all_data += cmd.subclass_address;
all_data += cmd.rw_flag;
for (int i = 0; i < data_len; i++)
all_data += data_in[i];
char checksum = all_data & 0xFF;
// ///////////////////////////////////////////
// CREATE OUTPUT BUFFER //////////////////////
buffer[0] = begin;
buffer[1] = size;
buffer[2] = cmd.device_address;
buffer[3] = cmd.class_address;
buffer[4] = cmd.subclass_address;
buffer[5] = cmd.rw_flag;
for (int i = 0; i < data_len; i++) // copy in the data to this array
buffer[i + 6] = data_in[i];
buffer[6 + data_len] = checksum;
buffer[7 + data_len] = end;
}

146
src/cmd/write.h Normal file
View File

@ -0,0 +1,146 @@
// Table 3-1, Information query commands
// Default data needs to be set to "none": `0x00`
enum InfoCommands
{
// Note on time:
// 0x20170101 indicates the time is January 1, 2017.
// Returns 5 bytes - Convert to ascii
Model,
// Returns 3 bytes - 0x011420 means v1.14.20
FPGA_Ver,
// Returns 4 bytes - Big endian time
FPGA_Comp_Time,
// Returns 3 bytes - 0x010410 means v1.4.10
Module_Software_Ver,
// Returns 4 bytes - Big endian time
Module_Software_Comp_Time,
// Returns 4 bytes - Big endian time
Camera_Calibration_Ver_Time,
// Returns 4 bytes
ISP_Parameter_Ver,
// Returns 1 byte - Loading: `0x00`, or Streaming: `0x01`
Init_State,
};
// Table 3-2, Function setting commands
enum FuncCommands
{
// TODO write only?
// Data none?
Manual_Shutter_Calibration,
// TODO write only?
// Data none?
Manual_Background_Correction,
// @brief Set shutter control. Data:
//
// `0x00` Automatic control off
//
// `0x01` Automatic switching, timing control
//
// `0x02` Automatic switching, temperature difference control
//
// `0x03` (Default) Full-automatic control
Automatic_Shutter_Control,
// Setting the shutter interval in minutes, 2 bytes.
// Default, 10min: `0x00 0x0A` "Not recommended for users to modify"
Automatic_Shutter_Switching_Interval,
// TODO
Vignetting_Correction,
// 1 byte, default: `0x32` (50), range: 0~100.
Brightness,
// 1 byte, default: `0x32` (50), range: 0~100.
Contrast,
// 1 byte, default: `0x32` (50), range: 0~100.
Digital_Enhancement,
// 1 byte, default: `0x32` (50), range: 0~100.
Static_De_Noising,
// 1 byte, default: `0x32` (50), range: 0~100.
Dynamic_De_Noising,
// `0x00`: Turn off the cursor display
//
// `0x0F`: Turn on the cursor display
//
// `0x02`: Cursor up
//
// `0x03`: Cursor down
//
// `0x04`: Cursor shifted left
//
// `0x05`: Cursor shifted right
//
// `0x06`: Cursor to the center
//
// `0x0D`: Add the pixel to the defective pixel table.
//
// `0x0E`: Remove the pixel from the defective pixel table.
//
// `0x2N`: Cursor up for N pixels (N: 0x1~0xF)
//
// `0x3N`: Cursor down for N pixels (N: 0x1~0xF)
//
// `0x4N`: Cursor shifted left for N pixels (N: 0x1~0xF)
//
// `0x5N`: Cursor shifted right for N pixels (N: 0x1~0xF)
Defective_Pixel_Correction,
// `0x00`: White Hot (Default)
//
// `0x01`: Black Hot
//
// `0x02`: Fusion 1
//
// `0x03`: Rainbow
//
// `0x04`: Fusion 2
//
// `0x05`: Iron Red 1
//
// `0x06`: Iron Red 2
//
// `0x07`: Dark Brown
//
// `0x08`: Color 1
//
// `0x09`: Color 2
//
// `0x0A`: Ice Fire
//
// `0x0B`: Rain
//
// `0x0C`: Green Hot
//
// `0x0D`: Red Hot
//
// `0x0E`: Deep Blue
Palette_Setting,
// Send `0x00` as data (default)(none)
Factory_Reset,
// Send `0x00` as data (default)(none)
Save_Settings,
// `0x00`: No mirroring.
//
// `0x01`: Central mirroring.
//
// `0x02`: Left and right mirroring.
//
// `0x03`: Up and down mirroring.
Mirroring,
};
class Addr
{
public:
uint8_t device_address, class_address, subclass_address, rw_flag;
explicit Addr(FuncCommands cmd);
explicit Addr(InfoCommands cmd);
};
/// @brief Sets up command to send to camera.
/// @param cmd Addr object of the command you want to send.
/// @param data_in Any data that should go along with it. If there is no data then send [0x00]
/// @param data_len Length of data array.
/// @param buffer Buffer to output into. This should be 8 larger than the data array.
void command(Addr cmd, uint8_t data_in[], int data_len, uint8_t buffer[]);

26
src/main.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <Arduino.h>
#include <HardwareSerial.h>
#include <SoftwareSerial.h>
#include "cmd/write.h"
SoftwareSerial cam_serial(3, 2);
void setup()
{
Serial.begin(115200);
cam_serial.begin(115200);
cam_serial.listen(); // this isn't strictly nsessray
}
void loop()
{
uint8_t buf[9];
for (unsigned char i = 0; i < 100; i++)
{
uint8_t data[] = {i};
command(*new Addr(FuncCommands::Brightness), data, 1, buf);
cam_serial.write(buf, 9); // software serial automatically flushes
delay(100);
}
}

11
test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html

33
test/test.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "unity.h"
#include "cmd/write.h"
void setUp() {}
void tearDown() {}
void test_byte_ordering() {
uint8_t expected[9] = {
0xF0, // Begin
0x05, // size ({data bytes}+4)
0x36, // dev addr
0x78, // class addr
0x02, // subclass addr
0x00, // r/w flag (0 = write, 1 = read)
0x64, // data
0x14, // Checksum (dev addr + sub addr + class addr + rw flag + data) & 0xFF
0xFF, // End
};
Addr cmd = *new Addr(FuncCommands::Brightness);
uint8_t data[] = {0x64};
uint8_t buf[1+8];
command(cmd, data, 1, buf);
TEST_ASSERT_EQUAL(expected, buf);
}
int main() {
UNITY_BEGIN();
RUN_TEST(test_byte_ordering);
return UNITY_END();
}