#include <stdio.h>
int main(void){
const char *s = "#include <stdio.h>%cint main(void){%c const char *s = %c%s%c;%c printf(s,10,10,34,s,34,10,10,10,10);%c return 0;%c}%c";
printf(s,10,10,34,s,34,10,10,10,10);
return 0;
}
This is actually something that can be found with a simple Google search, as it has been a common trick, challenge, or curiosity problem for decades.Wow, I just asked Copilot this:
write me a C program that when executed, generates text output that the same as the program's source code.
It "thinks" for a period then generates code. I posted that C into a simple empty Windows C project and it wasn't quite correct, so I then asked this:
that seems wrong, the generated line beginning "const char" is a single long line, whereas in the source its a series of short lines.
and you guys need to see what it does, I urge to try this when your next at your desks...
Oh, it generated this:
C:#include <stdio.h> int main(void){ const char *s = "#include <stdio.h>%cint main(void){%c const char *s = %c%s%c;%c printf(s,10,10,34,s,34,10,10,10,10);%c return 0;%c}%c"; printf(s,10,10,34,s,34,10,10,10,10); return 0; }
#include <stdio.h>
int main() {
char *s = "#include <stdio.h>\\n\\nint main() {\\n char *s = %c%s%c;\\n printf(s, 34, s, 34);\\n return 0;\\n}";
printf(s, 34, s, 34);
return 0;
}
Yes it is well known, but you should see the way the "thoughts" are rendered as the AI system is processing the problem, like a sci-fi movieThis is actually something that can be found with a simple Google search, as it has been a common trick, challenge, or curiosity problem for decades.
Asking Google "C program whose output is the program itself"
Returned, among MANY hits, the following page:
https://docs.vultr.com/clang/examples/display-its-own-source-code-as-output
Which has the following:
Another common approach, which I think is cheating, it to have the program print out it's own source code file. But that's pretty trivial. I think it needs to be an executable file that, when executed all by itself, prints out the contents of the source file that was used to produce it.Code:#include <stdio.h> int main() { char *s = "#include <stdio.h>\\n\\nint main() {\\n char *s = %c%s%c;\\n printf(s, 34, s, 34);\\n return 0;\\n}"; printf(s, 34, s, 34); return 0; }
Sorry but if you don't have an internet connection nowadays I think you will not download any TRM neither buy any board... You are out without any internet access.Few of us could write that without access to the internet, unless you've worked on that specific processor a great deal and have internalized a lot.
And I imagine few would use such heavy-handed functions as sprintf() and its brethren on an MCU.Here's my last and final example:
View attachment 355006
Few of us could write that without access to the internet, unless you've worked on that specific processor a great deal and have internalized a lot.
import machine
import time
# 1. Create an object to access the Real-Time Clock (RTC)
rtc = machine.RTC()
print("Starting clock. Press Ctrl+C to stop.")
try:
# 2. Create an infinite loop to continuously display the time
while True:
# 3. Get the current time from the RTC.
# It returns a tuple: (year, month, day, weekday, hour, minute, second, microsecond)
current_time = rtc.datetime()
# 4. Format the tuple into a nice, readable string
# The :02d adds a leading zero if the number is less than 10 (e.g., 09:05:03)
time_string = f"{current_time[0]}-{current_time[1]:02d}-{current_time[2]:02d} " \
f"{current_time[4]:02d}:{current_time[5]:02d}:{current_time[6]:02d}"
# 5. Print the formatted time string
print(time_string)
# 6. Wait for one second before the next update
time.sleep(1)
except KeyboardInterrupt:
# This allows you to stop the loop cleanly by pressing Ctrl+C
print("\nClock stopped.")
import time
import network
import ntptime
from machine import Pin, SPI
import st7789py as st7789
import vga1_16x32 as font
# --- Your Wi-Fi Credentials ---
WIFI_SSID = "YourSsid"
WIFI_PASSWORD = "Your_Password"
# --- Timezone Configuration ---
# EDT is UTC-4. The offset is in seconds.
TIMEZONE_OFFSET = -4 * 3600
# --- Your Display Configuration ---
tft = st7789.ST7789(
SPI(1, baudrate=30000000, sck=Pin(18), mosi=Pin(23)),
135,
240,
reset=Pin(4, Pin.OUT),
cs=Pin(15, Pin.OUT),
dc=Pin(2, Pin.OUT),
backlight=Pin(32, Pin.OUT),
rotation=1 # Set to landscape
)
def connect_wifi():
"""Connects the ESP32 to the Wi-Fi network."""
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('Connecting to network...')
tft.text(font, "Connecting...", 10, 50, st7789.YELLOW)
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
while not wlan.isconnected():
time.sleep(1)
print('Network config:', wlan.ifconfig())
tft.fill(st7789.BLACK) # Clear the screen
def set_time():
"""Sets the ESP32's real-time clock using NTP."""
print("Setting time from NTP server...")
tft.text(font, "Syncing Time...", 10, 50, st7789.CYAN)
# This sets the internal RTC to the current UTC time
ntptime.settime()
print("Time synced!")
tft.fill(st7789.BLACK)
def main():
"""Main function to run the display logic."""
tft.fill(st7789.BLACK)
# 1. Connect to the internet
connect_wifi()
# 2. Get the current time
set_time()
last_second = -1
# 3. Start the clock display loop
while True:
# Get the current time from the RTC and apply the timezone offset
current_time_utc = time.time()
local_time_tuple = time.localtime(current_time_utc + TIMEZONE_OFFSET)
# Unpack the tuple
year, month, day, hour, minute, second, _, _ = local_time_tuple
# Only redraw the screen if the second has changed
if second != last_second:
last_second = second
# Format the time into a HH:MM:SS string
# The :02d ensures that single-digit numbers get a leading zero (e.g., 09)
time_string = f"{hour:02d}:{minute:02d}:{second:02d}"
# Format the date into a MM/DD/YYYY string
date_string = f"{month:02d}/{day:02d}/{year}"
# Erase the previous time by drawing a black rectangle
tft.fill_rect(10, 50, 220, 80, st7789.BLACK)
# Draw the date and time strings
tft.text(font, date_string, 10, 50, st7789.WHITE)
tft.text(font, time_string, 10, 90, st7789.GREEN)
time.sleep_ms(100) # Small delay to prevent the loop from running too fast
main()
#include <xc.h>
// Configuration bits
#pragma config FOSC = INTOSCIO_EC // Internal oscillator, I/O function on OSC2
#pragma config WDTE = OFF // Watchdog timer disabled
#pragma config PWRTE = ON // Power-up timer enabled
#pragma config BOREN = ON // Brown-out reset enabled
#pragma config LVP = ON // Low-voltage programming enabled
// Define ADC channel and resolution
#define ADC_CHANNEL 0 // Channel 0
#define ADC_RESOLUTION 10 // 10-bit resolution
// UART Definitions
#define BAUD_RATE 9600 // Desired baud rate
#define _XTAL_FREQ 8000000 // Microcontroller's clock frequency (8MHz internal oscillator)
// Function to initialize ADC
void init_adc() {
// Set RA0 as analog input
ANSELAbits.ANSA0 = 1;
// Set RA0 as input pin
TRISAbits.TRISA0 = 1;
// ADCON1: Vref is Vdd and Vss, right-justified result
ADCON1 = 0x01; // ADCS = FOSC/8, ADCON1 = 0x01: ADCS = FOSC/8
// ADCON0: select channel, ADC on
ADCON0 = 0x00;
ADCON0bits.CHS = ADC_CHANNEL; // Select ADC channel
ADCON0bits.ADON = 1; // Turn on ADC
}
// Function to read ADC value
unsigned int read_adc() {
__delay_us(10); // Wait for acquisition time
ADCON0bits.GO_nDONE = 1; // Start conversion
while (ADCON0bits.GO_nDONE); // Wait for conversion to complete
return (ADRESH << 8) + ADRESL; // Read 10-bit result
}
// Function to initialize UART
void init_uart() {
// Set UART TX and RX pins
// For 12F1822, RC4 is TX and RC5 is RX (if using PPS)
// Here we'll configure it as per the default
TRISAbits.TRISA4 = 0; // Set RA4 as output for TX
APFCONbits.TXCKSEL = 1; // Map TX to RA4 (required for this specific pin)
// Baud rate setup
TXSTAbits.BRGH = 1; // High speed baud rate
BAUDCONbits.BRG16 = 1; // 16-bit baud rate generator
SPBRGL = ((_XTAL_FREQ / BAUD_RATE) / 4) - 1; // Low byte of baud rate
SPBRGH = (((_XTAL_FREQ / BAUD_RATE) / 4) - 1) >> 8; // High byte of baud rate
// Enable serial port and TX
RCSTAbits.SPEN = 1; // Enable serial port
TXSTAbits.TXEN = 1; // Enable transmit
}
// Function to send a single character via UART
void putch(char data) {
while (!TXSTAbits.TRMT); // Wait for transmit shift register to be empty
TXREG = data; // Load data to transmit register
}
// Function to print ADC value to serial
void print_adc_value(unsigned int value) {
// A simple function to print the integer value as a string
char buffer[6]; // Buffer to hold string
sprintf(buffer, "%u\r\n", value);
int i = 0;
while (buffer[i] != '\0') {
putch(buffer[i]);
i++;
}
}
// Main function
void main() {
// Disable all analog inputs first for cleaner setup
ANSELA = 0x00;
// Initialize the system
init_uart();
init_adc();
while (1) {
// Read ADC value
unsigned int adc_value = read_adc();
// Print ADC value to serial
print_adc_value(adc_value);
// Wait for a second before the next reading
__delay_ms(1000);
}
}
#include <xc.h>
#include <stdio.h>
// CONFIGURATION BITS
#pragma config FOSC = INTOSC // Internal oscillator
#pragma config WDTE = OFF // Watchdog Timer disabled
#pragma config PWRTE = OFF
#pragma config MCLRE = ON
#pragma config CP = OFF
#pragma config BOREN = ON
#pragma config CLKOUTEN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
#define _XTAL_FREQ 8000000
void UART_Init(void) {
TRISC6 = 0; // TX pin as output
TRISC7 = 1; // RX pin as input
SPBRG = 51; // Baud rate 9600 for 8MHz
TXSTAbits.BRGH = 1; // High speed
RCSTAbits.SPEN = 1; // Enable serial port
TXSTAbits.TXEN = 1; // Enable transmitter
}
void UART_Write(char data) {
while (!TXSTAbits.TRMT); // Wait until buffer is empty
TXREG = data;
}
void UART_Write_Text(const char *text) {
while (*text)
UART_Write(*text++);
}
void ADC_Init(void) {
ADCON0 = 0x01; // ADC ON, select channel AN0
ADCON1 = 0x80; // Right justify result, Vref = Vdd/Vss
TRISA0 = 1; // Set RA0/AN0 as input
}
unsigned int ADC_Read(void) {
__delay_ms(2); // Acquisition time
ADCON0bits.GO_nDONE = 1; // Start conversion
while (ADCON0bits.GO_nDONE); // Wait for completion
return ((ADRESH << 8) + ADRESL); // Combine result
}
void main(void) {
OSCCON = 0x72; // Set internal oscillator to 8MHz
UART_Init();
ADC_Init();
char buffer[10];
unsigned int adcValue;
while (1) {
adcValue = ADC_Read();
sprintf(buffer, "%u\r\n", adcValue); // Convert to string
UART_Write_Text(buffer);
__delay_ms(500);
}
}
It depends on where it's at in the programming scheme. I use the printf 'safe n' family to convert complex math results into standard formats like json/CSV on 8-bit machines where the full json libs are too heavy.And I imagine few would use such heavy-handed functions as sprintf() and its brethren on an MCU.
const char log_format[] = "^,%3.1f,%3.2f,%3.2f,%3.2f,%3.2f,%3.2f,%3.2f,%d.%01d,%d.%01d,%d.%01d,%d,%d,%d,1957,~EOT
snprintf((char*) log_buffer, MAX_B_BUF, log_format, LOG_VARS);
void state_mx_log_cb(void)
{
BM.log.volts_peak = (int16_t) cbuf[5];
BM.log.day = (int16_t) cbuf[14];
BM.log.kilowatt_hours = (int16_t) (((uint16_t) (cbuf[3] & 0xF0) >> 4) | (uint16_t) (cbuf[4] << 4));
BM.log.kilowatts_peak = (int16_t) (((uint16_t) (cbuf[13] & 0xFC) >> 2) | (uint16_t) (cbuf[12] << 6));
BM.log.bat_max = (int16_t) (((uint16_t) (cbuf[2] & 0xFC) >> 2) | (uint16_t) ((cbuf[3] & 0x0F) << 6));
BM.log.bat_min = (int16_t) (((uint16_t) (cbuf[10] & 0xC0) >> 6) | (uint16_t) ((cbuf[11] << 2) | ((cbuf[12] & 0x03) << 10)));
BM.log.amps_peak = (int16_t) (cbuf[1] | ((cbuf[2] & 0x03) << 8));
BM.log.amp_hours = (int16_t) (cbuf[9] | ((cbuf[10] & 0x3F) << 8));
BM.log.absorb_time = (int16_t) (cbuf[6] | ((cbuf[7] & 0x0F) << 8));
BM.log.float_time = (int16_t) (((cbuf[7] & 0xF0) >> 4) | (cbuf[8] << 4));
cmd_mx_log[5] = BM.log.select;
cmd_mx_log[7] = 0x16 + BM.log.select; // update the checksum
state = state_mx_status;
}

The internet connection remark was simply saying few people could write that code purely from memory, like Copilot we too need to look stuff up.Sorry but if you don't have an internet connection nowadays I think you will not download any TRM neither buy any board... You are out without any internet access.
Did you use the AI tool offline, without internet access?
Also, the TRM Is something to study a bit to know how the device is organised and how to use the library provided by the manufacturer, if they do. I checked in 30s the device ID 96 bits value in the TRM just searching into the TRM of that device.
Also, it is not needed to convert the value to a char string. I would never use a printf/sprintf on a MCU..
Also, where the characters are supposed to be printed to? Is it using a serial interface to stream them? Since no header include to UART/SPI etc. the AI tool might supposes that the ST is running an OS... This is very dangerous for someone without proper knowledge because it "teaches" bad practices, IMHO.
I asked Copilot if the function state_mx_log_cb could be simplified or made more readable, here's what it suggests:It depends on where it's at in the programming scheme. I use the printf 'safe n' family to convert complex math results into standard formats like json/CSV on 8-bit machines where the full json libs are too heavy.
I've timed and profiled the compiler results to be just about as good as custom code to mangle things into shape.C:const char log_format[] = "^,%3.1f,%3.2f,%3.2f,%3.2f,%3.2f,%3.2f,%3.2f,%d.%01d,%d.%01d,%d.%01d,%d,%d,%d,1957,~EOT snprintf((char*) log_buffer, MAX_B_BUF, log_format, LOG_VARS);
I know when it's good and bad, like using goto. This understanding of coding is where these 'helper' programs fail.
That sort of stuff is easy, the tricky part is to GROK the embedded register data to the bit, nibble and byte data formats to create standard data types for useful processing of that register data.
I do find the programs useful for documentation of my code, after it's working.C:void state_mx_log_cb(void) { BM.log.volts_peak = (int16_t) cbuf[5]; BM.log.day = (int16_t) cbuf[14]; BM.log.kilowatt_hours = (int16_t) (((uint16_t) (cbuf[3] & 0xF0) >> 4) | (uint16_t) (cbuf[4] << 4)); BM.log.kilowatts_peak = (int16_t) (((uint16_t) (cbuf[13] & 0xFC) >> 2) | (uint16_t) (cbuf[12] << 6)); BM.log.bat_max = (int16_t) (((uint16_t) (cbuf[2] & 0xFC) >> 2) | (uint16_t) ((cbuf[3] & 0x0F) << 6)); BM.log.bat_min = (int16_t) (((uint16_t) (cbuf[10] & 0xC0) >> 6) | (uint16_t) ((cbuf[11] << 2) | ((cbuf[12] & 0x03) << 10))); BM.log.amps_peak = (int16_t) (cbuf[1] | ((cbuf[2] & 0x03) << 8)); BM.log.amp_hours = (int16_t) (cbuf[9] | ((cbuf[10] & 0x3F) << 8)); BM.log.absorb_time = (int16_t) (cbuf[6] | ((cbuf[7] & 0x0F) << 8)); BM.log.float_time = (int16_t) (((cbuf[7] & 0xF0) >> 4) | (cbuf[8] << 4)); cmd_mx_log[5] = BM.log.select; cmd_mx_log[7] = 0x16 + BM.log.select; // update the checksum state = state_mx_status; }
View attachment 355018
Google 'AI'

Well its pretty impressive that it could look at you code for a couple seconds and even spot the opportunity for a macro, that's impressive refactoring skill.Screw macros, they are a pit of hell for low-level embedded programming, they don't help in a lot of cases, it only provides an obfuscation of what's important in that section of code. I don't want it to be abstracted, I want the source to be expansive, clear and Naked as a jaybird on each line because there will be only one parsing routine to do the data extraction. They have a time and place, just not here IMO. It's a style of code, not critical for correctness. Correctness is what's critical and that's what's missing to make embedded more productive, not hints on coding styles.
Let the compiler optimizer make it better. I trust the compilers output, I don't trust the stupid program 'AI' to give bad advice because it has no understanding of why, only the rote answers given to rookies in every CS class.

This is not the way to work. You download the TRM and save it to your HD to review it when needed...The internet connection remark was simply saying few people could write that code purely from memory
Is the code using a printf into an MCU to print something to the display? Good luck with AI code.Finally, who said anything about printing? you aren't assuming things are you?